Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions 1-js/06-advanced-functions/01-recursion/01-sum-to/solution.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
The solution using a loop:
A solução usando um laço:

```js run
function sumTo(n) {
Expand All @@ -12,7 +12,7 @@ function sumTo(n) {
alert( sumTo(100) );
```

The solution using recursion:
A solução usando recursão:

```js run
function sumTo(n) {
Expand All @@ -23,7 +23,7 @@ function sumTo(n) {
alert( sumTo(100) );
```

The solution using the formula: `sumTo(n) = n*(n+1)/2`:
A solução usando a fórmula: `sumTo(n) = n*(n+1)/2`:

```js run
function sumTo(n) {
Expand All @@ -33,8 +33,8 @@ function sumTo(n) {
alert( sumTo(100) );
```

P.S. Naturally, the formula is the fastest solution. It uses only 3 operations for any number `n`. The math helps!
P.S. Naturalmente, a fórmula é a solução mais rápida. Ela usa só 3 operações para qualquer número `n`. A matemática ajuda!

The loop variant is the second in terms of speed. In both the recursive and the loop variant we sum the same numbers. But the recursion involves nested calls and execution stack management. That also takes resources, so it's slower.
A variante com laço é a segunda em termos de velocidade. Tanto na variante recursiva quanto na de laço, somamos os mesmos números. Mas a recursão envolve chamadas aninhadas e gerenciamento da pilha de execução. Isso também consome recursos, então é mais lenta.

P.P.S. Some engines support the "tail call" optimization: if a recursive call is the very last one in the function, with no other calculations performed, then the outer function will not need to resume the execution, so the engine doesn't need to remember its execution context. That removes the burden on memory. But if the JavaScript engine does not support tail call optimization (most of them don't), there will be an error: maximum stack size exceeded, because there's usually a limitation on the total stack size.
P.P.S. Alguns motores suportam a otimização de "chamada de cauda" (*tail call*): se uma chamada recursiva é a última da função, sem nenhum outro cálculo realizado depois, então a função externa não vai precisar retomar a execução, então o motor não precisa lembrar seu contexto de execução. Isso remove a sobrecarga na memória. Mas, se o motor do JavaScript não suportar a otimização de chamada de cauda (a maioria não suporta), vai haver um erro: tamanho máximo da pilha excedido, porque normalmente existe uma limitação no tamanho total da pilha.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A frase repete "então" duas vezes ("...não vai precisar retomar a execução, então o motor..."), o que dificulta a leitura. Sugestão: "...não vai precisar retomar a execução e, portanto, o motor não precisa lembrar seu contexto de execução."

22 changes: 11 additions & 11 deletions 1-js/06-advanced-functions/01-recursion/01-sum-to/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ importance: 5

---

# Sum all numbers till the given one
# Some todos os números até o dado

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Título ambíguo: "até o dado" pode ser lido como o substantivo "dado" (de jogar). Sugestão: "# Some todos os números até o número dado".


Write a function `sumTo(n)` that calculates the sum of numbers `1 + 2 + ... + n`.
Escreva uma função `sumTo(n)` que calcule a soma dos números `1 + 2 + ... + n`.

For instance:
Por exemplo:

```js no-beautify
sumTo(1) = 1
Expand All @@ -17,20 +17,20 @@ sumTo(4) = 4 + 3 + 2 + 1 = 10
sumTo(100) = 100 + 99 + ... + 2 + 1 = 5050
```

Make 3 solution variants:
Faça 3 variantes de solução:

1. Using a for loop.
2. Using a recursion, cause `sumTo(n) = n + sumTo(n-1)` for `n > 1`.
3. Using the [arithmetic progression](https://en.wikipedia.org/wiki/Arithmetic_progression) formula.
1. Usando um laço for.
2. Usando recursão, já que `sumTo(n) = n + sumTo(n-1)` para `n > 1`.
3. Usando a fórmula da [progressão aritmética](https://pt.wikipedia.org/wiki/Progress%C3%A3o_aritm%C3%A9tica).

An example of the result:
Um exemplo do resultado:

```js
function sumTo(n) { /*... your code ... */ }
function sumTo(n) { /*... seu código ... */ }

alert( sumTo(100) ); // 5050
```

P.S. Which solution variant is the fastest? The slowest? Why?
P.S. Qual variante de solução é a mais rápida? A mais lenta? Por quê?

P.P.S. Can we use recursion to count `sumTo(100000)`?
P.P.S. Podemos usar recursão para calcular `sumTo(100000)`?
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
By definition, a factorial `n!` can be written as `n * (n-1)!`.
Por definição, um fatorial `n!` pode ser escrito como `n * (n-1)!`.

In other words, the result of `factorial(n)` can be calculated as `n` multiplied by the result of `factorial(n-1)`. And the call for `n-1` can recursively descend lower, and lower, till `1`.
Em outras palavras, o resultado de `factorial(n)` pode ser calculado como `n` multiplicado pelo resultado de `factorial(n-1)`. E a chamada para `n-1` pode descer recursivamente mais e mais, até `1`.

```js run
function factorial(n) {
Expand All @@ -10,7 +10,7 @@ function factorial(n) {
alert( factorial(5) ); // 120
```

The basis of recursion is the value `1`. We can also make `0` the basis here, doesn't matter much, but gives one more recursive step:
A base da recursão é o valor `1`. Também podemos fazer de `0` a base aqui, não faz muita diferença, mas dá mais um passo recursivo:

```js run
function factorial(n) {
Expand Down
12 changes: 6 additions & 6 deletions 1-js/06-advanced-functions/01-recursion/02-factorial/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ importance: 4

---

# Calculate factorial
# Calcule o fatorial

The [factorial](https://en.wikipedia.org/wiki/Factorial) of a natural number is a number multiplied by `"number minus one"`, then by `"number minus two"`, and so on till `1`. The factorial of `n` is denoted as `n!`
O [fatorial](https://pt.wikipedia.org/wiki/Fatorial) de um número natural é um número multiplicado por `"número menos um"`, depois por `"número menos dois"`, e assim por diante até `1`. O fatorial de `n` é representado como `n!`

We can write a definition of factorial like this:
Podemos escrever uma definição de fatorial assim:

```js
n! = n * (n - 1) * (n - 2) * ...*1
```

Values of factorials for different `n`:
Valores de fatoriais para diferentes `n`:

```js
1! = 1
Expand All @@ -22,10 +22,10 @@ Values of factorials for different `n`:
5! = 5 * 4 * 3 * 2 * 1 = 120
```

The task is to write a function `factorial(n)` that calculates `n!` using recursive calls.
A tarefa é escrever uma função `factorial(n)` que calcule `n!` usando chamadas recursivas.

```js
alert( factorial(5) ); // 120
```

P.S. Hint: `n!` can be written as `n * (n-1)!` For instance: `3! = 3*2! = 3*2*1! = 6`
P.S. Dica: `n!` pode ser escrito como `n * (n-1)!` Por exemplo: `3! = 3*2! = 3*2*1! = 6`
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The first solution we could try here is the recursive one.
A primeira solução que poderíamos tentar aqui é a recursiva.

Fibonacci numbers are recursive by definition:
Os números de Fibonacci são recursivos por definição:

```js run
function fib(n) {
Expand All @@ -9,14 +9,14 @@ function fib(n) {

alert( fib(3) ); // 2
alert( fib(7) ); // 13
// fib(77); // will be extremely slow!
// fib(77); // vai ser extremamente lento!
```

...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.
...Mas, para valores grandes de `n`, é muito lenta. Por exemplo, `fib(77)` pode travar o motor por um tempo, consumindo todos os recursos da CPU.

That's because the function makes too many subcalls. The same values are re-evaluated again and again.
Isso acontece porque a função faz muitas subchamadas. Os mesmos valores são reavaliados repetidamente.

For instance, let's see a piece of calculations for `fib(5)`:
Por exemplo, vamos ver um trecho dos cálculos para `fib(5)`:

```js no-beautify
...
Expand All @@ -25,68 +25,68 @@ fib(4) = fib(3) + fib(2)
...
```

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.
Aqui podemos ver que o valor de `fib(3)` é necessário tanto para `fib(5)` quanto para `fib(4)`. Então `fib(3)` vai ser chamado e avaliado duas vezes, de forma completamente independente.

Here's the full recursion tree:
Aqui está a árvore de recursão completa:

![fibonacci recursion tree](fibonacci-recursion-tree.svg)
![árvore de recursão de fibonacci](fibonacci-recursion-tree.svg)

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`.
Podemos notar claramente que `fib(3)` é avaliado duas vezes e `fib(2)` é avaliado três vezes. O total de cálculos cresce muito mais rápido do que `n`, tornando-se enorme mesmo para `n=77`.

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.
Podemos otimizar isso lembrando os valores já avaliados: se um valor, digamos `fib(3)`, for calculado uma vez, então podemos simplesmente reutilizá-lo em cálculos futuros.

Another variant would be to give up recursion and use a totally different loop-based algorithm.
Outra variante seria abrir mão da recursão e usar um algoritmo totalmente diferente, baseado em laço.

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.
Em vez de ir de `n` para baixo, até valores menores, podemos fazer um laço que começa em `1` e `2`, depois obtém `fib(3)` como a soma deles, depois `fib(4)` como a soma dos dois valores anteriores, depois `fib(5)` e vai subindo e subindo, até chegar ao valor necessário. A cada passo, só precisamos lembrar os dois valores anteriores.

Here are the steps of the new algorithm in details.
Aqui estão os passos do novo algoritmo em detalhes.

The start:
O início:

```js
// a = fib(1), b = fib(2), these values are by definition 1
// a = fib(1), b = fib(2), esses valores são 1 por definição
let a = 1, b = 1;

// get c = fib(3) as their sum
// obtém c = fib(3) como a soma deles
let c = a + b;

/* we now have fib(1), fib(2), fib(3)
/* agora temos fib(1), fib(2), fib(3)
a b c
1, 1, 2
*/
```

Now we want to get `fib(4) = fib(2) + fib(3)`.
Agora queremos obter `fib(4) = fib(2) + fib(3)`.

Let's shift the variables: `a,b` will get `fib(2),fib(3)`, and `c` will get their sum:
Vamos deslocar as variáveis: `a,b` vão receber `fib(2),fib(3)`, e `c` vai receber a soma deles:

```js no-beautify
a = b; // now a = fib(2)
b = c; // now b = fib(3)
a = b; // agora a = fib(2)
b = c; // agora b = fib(3)
c = a + b; // c = fib(4)

/* now we have the sequence:
/* agora temos a sequência:
a b c
1, 1, 2, 3
*/
```

The next step gives another sequence number:
O próximo passo dá outro número da sequência:

```js no-beautify
a = b; // now a = fib(3)
b = c; // now b = fib(4)
a = b; // agora a = fib(3)
b = c; // agora b = fib(4)
c = a + b; // c = fib(5)

/* now the sequence is (one more number):
/* agora a sequência é (mais um número):
a b c
1, 1, 2, 3, 5
*/
```

...And so on until we get the needed value. That's much faster than recursion and involves no duplicate computations.
...E assim por diante até obtermos o valor necessário. Isso é muito mais rápido do que a recursão e não envolve cálculos duplicados.

The full code:
O código completo:

```js run
function fib(n) {
Expand All @@ -105,6 +105,6 @@ alert( fib(7) ); // 13
alert( fib(77) ); // 5527939700884757
```

The loop starts with `i=3`, because the first and the second sequence values are hard-coded into variables `a=1`, `b=1`.
O laço começa com `i=3`, porque o primeiro e o segundo valores da sequência já estão fixados nas variáveis `a=1`, `b=1`.

The approach is called [dynamic programming bottom-up](https://en.wikipedia.org/wiki/Dynamic_programming).
Essa abordagem é chamada de [programação dinâmica bottom-up](https://pt.wikipedia.org/wiki/Programa%C3%A7%C3%A3o_din%C3%A2mica) (de baixo para cima).
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,24 @@ importance: 5

---

# Fibonacci numbers
# Números de Fibonacci

The sequence of [Fibonacci numbers](https://en.wikipedia.org/wiki/Fibonacci_number) has the formula <code>F<sub>n</sub> = F<sub>n-1</sub> + F<sub>n-2</sub></code>. In other words, the next number is a sum of the two preceding ones.
A sequência dos [números de Fibonacci](https://pt.wikipedia.org/wiki/N%C3%BAmero_de_Fibonacci) tem a fórmula <code>F<sub>n</sub> = F<sub>n-1</sub> + F<sub>n-2</sub></code>. Em outras palavras, o próximo número é a soma dos dois anteriores.

First two numbers are `1`, then `2(1+1)`, then `3(1+2)`, `5(2+3)` and so on: `1, 1, 2, 3, 5, 8, 13, 21...`.
Os dois primeiros números são `1`, depois `2(1+1)`, depois `3(1+2)`, `5(2+3)` e assim por diante: `1, 1, 2, 3, 5, 8, 13, 21...`.

Fibonacci numbers are related to the [Golden ratio](https://en.wikipedia.org/wiki/Golden_ratio) and many natural phenomena around us.
Os números de Fibonacci estão relacionados à [proporção áurea](https://pt.wikipedia.org/wiki/Propor%C3%A7%C3%A3o_%C3%A1urea) e a muitos fenômenos naturais ao nosso redor.

Write a function `fib(n)` that returns the `n-th` Fibonacci number.
Escreva uma função `fib(n)` que retorne o `n-ésimo` número de Fibonacci.

An example of work:
Um exemplo de funcionamento:

```js
function fib(n) { /* your code */ }
function fib(n) { /* seu código */ }

alert(fib(3)); // 2
alert(fib(7)); // 13
alert(fib(77)); // 5527939700884757
```

P.S. The function should be fast. The call to `fib(77)` should take no more than a fraction of a second.
P.S. A função deve ser rápida. A chamada a `fib(77)` deve levar no máximo uma fração de segundo.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Loop-based solution
# Solução baseada em laço

The loop-based variant of the solution:
A variante da solução baseada em laço:

```js run
let list = {
Expand Down Expand Up @@ -30,7 +30,7 @@ function printList(list) {
printList(list);
```

Please note that we use a temporary variable `tmp` to walk over the list. Technically, we could use a function parameter `list` instead:
Observe que usamos uma variável temporária `tmp` para percorrer a lista. Tecnicamente, poderíamos usar o próprio parâmetro da função, `list`, em vez disso:

```js
function printList(list) {
Expand All @@ -43,15 +43,15 @@ function printList(list) {
}
```

...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.
...Mas isso não seria sensato. No futuro, podemos precisar estender uma função, fazer outra coisa com a lista. Se mudarmos `list`, perdemos essa capacidade.

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.
Falando em bons nomes de variáveis, `list` aqui é a própria lista. O primeiro elemento dela. E deveria continuar assim. Isso é claro e confiável.

From the other side, the role of `tmp` is exclusively a list traversal, like `i` in the `for` loop.
Por outro lado, o papel de `tmp` é exclusivamente percorrer a lista, como o `i` num laço `for`.

# Recursive solution
# Solução recursiva

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`:
A variante recursiva de `printList(list)` segue uma lógica simples: para exibir uma lista, devemos exibir o elemento atual `list`, depois fazer o mesmo para `list.next`:

```js run
let list = {
Expand All @@ -70,19 +70,19 @@ let list = {

function printList(list) {

alert(list.value); // output the current item
alert(list.value); // exibe o item atual

if (list.next) {
printList(list.next); // do the same for the rest of the list
printList(list.next); // faz o mesmo para o resto da lista
}

}

printList(list);
```

Now what's better?
Agora, o que é melhor?

Technically, the loop is more effective. These two variants do the same, but the loop does not spend resources for nested function calls.
Tecnicamente, o laço é mais eficiente. As duas variantes fazem a mesma coisa, mas o laço não gasta recursos com chamadas de função aninhadas.

From the other side, the recursive variant is shorter and sometimes easier to understand.
Por outro lado, a variante recursiva é mais curta e, às vezes, mais fácil de entender.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ importance: 5

---

# Output a single-linked list
# Exiba uma lista encadeada simples

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Terminologia inconsistente: o artigo traduz "linked list" como "lista ligada", mas as tarefas 04 e 05 usam "lista encadeada simples". A linha 7 diz "como descrito no capítulo info:recursion", só que o capítulo nunca usa "encadeada". Sugiro escolher um único termo nos 3 arquivos (por exemplo, "lista ligada simples").


Let's say we have a single-linked list (as described in the chapter <info:recursion>):
Digamos que temos uma lista encadeada simples (como descrito no capítulo <info:recursion>):

```js
let list = {
Expand All @@ -22,8 +22,8 @@ let list = {
};
```

Write a function `printList(list)` that outputs list items one-by-one.
Escreva uma função `printList(list)` que exiba os itens da lista um por um.

Make two variants of the solution: using a loop and using recursion.
Faça duas variantes da solução: usando um laço e usando recursão.

What's better: with recursion or without it?
O que é melhor: com recursão ou sem ela?
Loading