You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The first solution we could try here is the recursive one.
1
+
가장 먼저 떠올릴 수 있는 방법은 재귀를 사용하는 것입니다.
2
2
3
-
Fibonacci numbers are recursive by definition:
3
+
정의에서도 알 수 있듯이 피보나치 수열은 재귀를 사용해 구현할 수 있습니다.
4
4
5
5
```js run
6
6
functionfib(n) {
@@ -12,11 +12,11 @@ alert( fib(7) ); // 13
12
12
// fib(77); // will be extremely slow!
13
13
```
14
14
15
-
...But for big values of `n` it's very slow. For instance, `fib(77)` may hang up the engine for some time eating all CPU resources.
15
+
그런데 이렇게 구현하면 `n`이 클 경우 속도가 느려집니다. `fib(77)`를 호출하면 CPU 리소스를 다 잡아먹어서 잠시 엔진이 멈출 수 있습니다.
16
16
17
-
That's because the function makes too many subcalls. The same values are re-evaluated again and again.
17
+
이는 함수 호출 도중에 수많은 서브 호출이 일어나기 때문입니다. 같은 값들이 여러 번 평가되면서 이런 일이 발생하죠.
18
18
19
-
For instance, let's see a piece of calculations for `fib(5)`:
19
+
`fib(5)`의 계산 과정을 살펴보며 자세히 알아봅시다.
20
20
21
21
```js no-beautify
22
22
...
@@ -25,68 +25,68 @@ fib(4) = fib(3) + fib(2)
25
25
...
26
26
```
27
27
28
-
Here we can see that the value of `fib(3)` is needed for both `fib(5)` and `fib(4)`. So `fib(3)` will be called and evaluated two times completely independently.
28
+
`fib(3)`은 `fib(5)`와 `fib(4)`를 계산할 때 모두 필요합니다. 그렇기 때문에 `fib(3)`은 완전히 다른 두 곳에서 독립적으로 호출되고 평가되죠.
We can clearly notice that `fib(3)` is evaluated two times and `fib(2)` is evaluated three times. The total amount of computations grows much faster than `n`, making it enormous even for `n=77`.
34
+
그림을 보니 `fib(3)`은 두 번 평가된다는 것이 좀 더 명확히 보이네요. `fib(2)`는 세 번이나 평가되기까지 합니다. `n`이 증가하는 속도보다 전체 연산 횟수가 더 빨리 증가한다는 것을 아실 수 있겠죠? `77`은 그리 큰 숫자가 아니지만 `n=77`일 경우 엄청난 수의 연산이 일어난다는 것을 알 수 있습니다.
35
35
36
-
We can optimize that by remembering already-evaluated values: if a value of say `fib(3)` is calculated once, then we can just reuse it in future computations.
36
+
이런 단점을 극복하기 위해 이미 평가된 값을 어딘가에 저장해놓는 식으로 최적화를 할 수 있습니다. `fib(3)`의 계산이 끝나면 이 결과를 어딘가에 저장해 놓았다가 같은 값이 필요할 때 저장된 값을 불러오는 식으로 말이죠.
37
37
38
-
Another variant would be to give up recursion and use a totally different loop-based algorithm.
38
+
또 다른 방법으론 재귀가 아닌 반복문을 기반으로 하는 알고리즘을 짜는 것입니다.
39
39
40
-
Instead of going from `n` down to lower values, we can make a loop that starts from `1` and `2`, then gets`fib(3)` as their sum, then `fib(4)` as the sum of two previous values, then `fib(5)` and goes up and up, till it gets to the needed value. On each step we only need to remember two previous values.
40
+
`n`부터 시작해 숫자를 하나씩 줄이며 원하는 값을 구하는 대신 `1`과 `2`로 시작하는 반복문으로`fib(3)`을 구하고, 이를 기반으로 `fib(4)`를 구하고, 또 이를 기반으로 `fib(5)`를 구하는 식으로 알고리즘을 구현할 수 있을 겁니다. 이렇게 알고리즘을 구현하면 이전 두 항의 값만 저장하면 되죠.
41
41
42
-
Here are the steps of the new algorithm in details.
42
+
반복문을 기반으로 하는 알고리즘을 좀 더 자세히 살펴보겠습니다.
43
43
44
-
The start:
44
+
시작은 다음과 같습니다.
45
45
46
46
```js
47
-
// a = fib(1), b = fib(2), these values are by definition 1
47
+
// a = fib(1), b = fib(2), 처음 두 항은 1이라는 정의에 의해 이렇게 값을 할당하였습니다.
48
48
let a =1, b =1;
49
49
50
-
//get c = fib(3) as their sum
50
+
// c = fib(3), 세 번째 항은 첫 번째 항과 두 번째 항의 합입니다.
51
51
let c = a + b;
52
52
53
-
/*we now have fib(1), fib(2), fib(3)
53
+
/* fib(1), fib(2), fib(3)을 구했습니다.
54
54
a b c
55
55
1, 1, 2
56
56
*/
57
57
```
58
58
59
-
Now we want to get `fib(4) = fib(2) + fib(3)`.
59
+
이제 `fib(2)`와 `fib(3)`을 더해 `fib(4)`를 구해봅시다.
60
60
61
-
Let's shift the variables: `a,b` will get `fib(2),fib(3)`, and `c` will get their sum:
61
+
`a`에 기존 `b`를, `b`에 기존 `c`를 할당하고, `c`는 `a`와 `b`의 합이 되도록 합시다.
62
62
63
63
```js no-beautify
64
-
a = b; //now a = fib(2)
65
-
b = c; //now b = fib(3)
64
+
a = b; // a = fib(2)
65
+
b = c; // b = fib(3)
66
66
c = a + b; // c = fib(4)
67
67
68
-
/*now we have the sequence:
68
+
/*다음과 같은 수열을 얻을 수 있습니다.
69
69
a b c
70
70
1, 1, 2, 3
71
71
*/
72
72
```
73
73
74
-
The next step gives another sequence number:
74
+
같은 과정을 반복해 다음 수를 얻어봅시다.
75
75
76
76
```js no-beautify
77
77
a = b; // now a = fib(3)
78
78
b = c; // now b = fib(4)
79
79
c = a + b; // c = fib(5)
80
80
81
-
/*now the sequence is (one more number):
81
+
/*다음과 같은 수열을 얻을 수 있습니다.
82
82
a b c
83
83
1, 1, 2, 3, 5
84
84
*/
85
85
```
86
86
87
-
...And so on until we get the needed value. That's much faster than recursion and involves no duplicate computations.
87
+
목표로 하는 값을 얻을 때까지 위와 같은 과정을 반복하면 되겠죠? 이렇게 하면 재귀를 사용하는 방법보다 연산 속도도 빠르고 중복되는 계산도 없다는 장점이 있습니다.
88
88
89
-
The full code:
89
+
반복문을 사용한 전체 코드는 다음과 같습니다.
90
90
91
91
```js run
92
92
functionfib(n) {
@@ -105,6 +105,6 @@ alert( fib(7) ); // 13
105
105
alert( fib(77) ); // 5527939700884757
106
106
```
107
107
108
-
The loop starts with `i=3`, because the first and the second sequence values are hard-coded into variables `a=1`, `b=1`.
108
+
반복문 내 `i`는 `3`부터 시작합니다. 피보나치 수열의 첫 번째 항과 두 번째 항은 `a=1`, `b=1`로 하드코딩 했기 때문입니다.
109
109
110
-
The approach is called [dynamic programming bottom-up](https://en.wikipedia.org/wiki/Dynamic_programming).
110
+
이런 접근 방법은 [동적 계획법(dynamic programming)](https://en.wikipedia.org/wiki/Dynamic_programming)이라 부릅니다.
Copy file name to clipboardExpand all lines: 1-js/06-advanced-functions/01-recursion/03-fibonacci-numbers/task.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,11 +3,11 @@ importance: 5
3
3
---
4
4
# 피보나치 수 계산하기
5
5
6
-
[피보나치 수](https://ko.wikipedia.org/wiki/%ED%94%BC%EB%B3%B4%EB%82%98%EC%B9%98_%EC%88%98)는 첫째 및 둘째 항이 1이며 그 뒤의 모든 항은 바로 앞 두 항의 합인 수열로, <code>F<sub>n</sub> = F<sub>n-1</sub> + F<sub>n-2</sub></code>이라는 공식으로 표현됩니다.
6
+
[피보나치 수](https://ko.wikipedia.org/wiki/%ED%94%BC%EB%B3%B4%EB%82%98%EC%B9%98_%EC%88%98)는 첫째 및 둘째 항이 1이며 그 뒤의 모든 항은 바로 앞 두 항의 합인 수열로, <code>F<sub>n</sub> = F<sub>n-1</sub> + F<sub>n-2</sub></code>이라는 공식으로 표현됩니다.
7
7
8
8
수열의 처음 두 숫자는 `1`이고, 그 다음 항들은 `2(1+1)`,`3(1+2)`,`5(2+3)`가 됩니다(`1, 1, 2, 3, 5 , 8, 13, 21 ...`).
9
9
10
-
피보나치 수는 [황금 비율](https://en.wikipedia.org/wiki/Golden_ratio)등의 우리 주변을 둘러싼 수많은 자연 현상과 관련이 있습니다.
10
+
피보나치 수는 [황금 비율](https://en.wikipedia.org/wiki/Golden_ratio)등 우리 주변을 둘러싼 수많은 자연 현상과 관련이 있습니다.
Copy file name to clipboardExpand all lines: 1-js/06-advanced-functions/01-recursion/04-output-single-linked-list/solution.md
+13-13Lines changed: 13 additions & 13 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
-
# Loop-based solution
1
+
# 반복문을 기반으로 하는 방법
2
2
3
-
The loop-based variant of the solution:
3
+
반복문을 사용한 답안은 다음과 같습니다.
4
4
5
5
```js run
6
6
let list = {
@@ -30,7 +30,7 @@ function printList(list) {
30
30
printList(list);
31
31
```
32
32
33
-
Please note that we use a temporary variable `tmp` to walk over the list. Technically, we could use a function parameter `list` instead:
33
+
여기서 주목해야 할 점은 리스트를 임시 변수 `tmp`에 저장하고 사용했다는 것입니다. 아래처럼 매개변수 `list`를 그대로 사용해도 되는데 말이죠.
34
34
35
35
```js
36
36
functionprintList(list) {
@@ -43,15 +43,15 @@ function printList(list) {
43
43
}
44
44
```
45
45
46
-
...But that would be unwise. In the future we may need to extend a function, do something else with the list. If we change `list`, then we lose such ability.
46
+
그런데 매개변수 `list`를 바로 사용하는 건 그다지 현명한 선택은 아닙니다. 나중에 함수를 확장할 때 `list`를 가지고 뭔가 해야 하는 경우가 생길 수 있기 때문이죠. 어떤 일 때문인지는 몰라도 `while`문 앞에서 `list`가 변경되면 우리가 짠 코드는 제대로 동작하지 않을 겁니다.
47
47
48
-
Talking about good variable names, `list` here is the list itself. The first element of it. And it should remain like that. That's clear and reliable.
48
+
좋은 변수명이 무엇인가를 생각해 봤을 때도 리스트를 임시 변수 `tmp`에 저장하는 게 좋습니다. `list`에는 리스트 그 자체가 저장되어있는 게 좋죠.
49
49
50
-
From the other side, the role of`tmp` is exclusively a list traversal, like `i` in the `for` loop.
50
+
`tmp`는 리스트를 순회하기 위한 용도로 쓰였기 때문에`tmp`라고 명명하는 게 좋습니다. `for`문의 `i`처럼 말이죠.
51
51
52
-
# Recursive solution
52
+
# 재귀를 기반으로 하는 방법
53
53
54
-
The recursive variant of `printList(list)` follows a simple logic: to output a list we should output the current element `list`, then do the same for `list.next`:
54
+
재귀를 사용해 만든 `printList(list)`는 아주 간단한 로직을 기반으로 합니다. "리스트를 출력할 때는 현재 요소 `list`를 출력하고, 같은 방법을 사용해 `list.next`를 출력한다."라는 로직이죠.
55
55
56
56
```js run
57
57
let list = {
@@ -70,19 +70,19 @@ let list = {
70
70
71
71
functionprintList(list) {
72
72
73
-
alert(list.value); //output the current item
73
+
alert(list.value); //현재 요소를 출력합니다.
74
74
75
75
if (list.next) {
76
-
printList(list.next); //do the same for the rest of the list
76
+
printList(list.next); //같은 방법을 사용해 나머지 요소를 출력합니다.
77
77
}
78
78
79
79
}
80
80
81
81
printList(list);
82
82
```
83
83
84
-
Now what's better?
84
+
이제 두 방법을 비교해봅시다.
85
85
86
-
Technically, the loop is more effective. These two variants do the same, but the loop does not spend resources for nested function calls.
86
+
반복문을 사용하면 리소스를 좀 더 효율적으로 사용합니다. 두 방법의 반환 값은 같지만, 반복문을 사용한 방법에선 중첩 함수를 호출하는데 추가적인 리소스를 쓰지 않기 때문입니다.
87
87
88
-
From the other side, the recursive variant is shorter and sometimes easier to understand.
Copy file name to clipboardExpand all lines: 1-js/06-advanced-functions/01-recursion/05-output-single-linked-list-reverse/solution.md
+8-8Lines changed: 8 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,8 +1,8 @@
1
-
# Using a recursion
1
+
# 재귀를 기반으로 하는 방법
2
2
3
-
The recursive logic is a little bit tricky here.
3
+
재귀를 사용한 방법은 조금 까다롭습니다.
4
4
5
-
We need to first output the rest of the list and *then* output the current one:
5
+
리스트의 나머지 요소들을 출력한 *다음에* 현재 요소를 출력해야 하죠.
6
6
7
7
```js run
8
8
let list = {
@@ -31,13 +31,13 @@ function printReverseList(list) {
31
31
printReverseList(list);
32
32
```
33
33
34
-
# Using a loop
34
+
# 반복문을 기반으로 하는 방법
35
35
36
-
The loop variant is also a little bit more complicated then the direct output.
36
+
리스트를 원래 순서대로 출력하는 방법보다 역시 까다롭습니다.
37
37
38
-
There is no way to get the last value in our `list`. We also can't "go back".
38
+
`list`의 마지막 값을 바로 구할 수 있는 방법이 없기 때문입니다. 마지막 값을 시작으로 '역행'할 수 없는 상황이죠.
39
39
40
-
So what we can do is to first go through the items in the direct order and remember them in an array, and then output what we remembered in the reverse order:
40
+
따라서 우리는 원래 순서대로 요소들을 하나씩 거슬러 올라가면서 각 요소를 배열에 저장해 놓고, 마지막 요소에 도달했을 때 배열에 저장된 요소들을 거꾸로 출력하는 방법을 사용할 수 있을 겁니다.
41
41
42
42
```js run
43
43
let list = {
@@ -71,4 +71,4 @@ function printReverseList(list) {
71
71
printReverseList(list);
72
72
```
73
73
74
-
Please note that the recursive solution actually does exactly the same: it follows the list, remembers the items in the chain of nested calls (in the execution context stack), and then outputs them.
74
+
여기서 주목할 점은 재귀를 사용한 방법과 반복문을 사용한 방법이 완전히 동일한 접근 방식을 취했다는 것입니다. 리스트를 앞에서부터 따라가면서 각 요소를 실행 컨텍스트 스택에 저장해 놓았다가 스택 맨 위에서부터 요소를 차례대로 출력하였습니다.
0 commit comments