I am working my way through the javascript course on freecodecamp and im confused with the lesson on recursive functions.
I am having difficulty understanding the following code:
function sum(arr, n) {
if(n<=0) {
return 0;
} else {
return sum(arr, n-1) + arr[n-1];
}
}
sum([10,20,30,40], 3);
The specific part im struggling with is this:
arr[n-1];
would the return line not be returning sum([10,20,30,40], 3-1) + arr[3-1] resulting in 30+30 = 60?
Any help with this would be greatly appreciated. Or even pointing me in the right direction to look into this further.
Thanks
Let's write the original code in a more intuitive way by putting arr[n-1] first. This way we can keep expanding each call to sum() to the right.
But first let's note down what sum(arr, n) call will return for each n
if n > 0 => arr[n-1] + sum(arr, n-1)
if n == 0 => 0
n == 3 => arr[2] + sum(arr, 2)
n == 2 => arr[1] + sum(arr, 1)
n == 1 => arr[0] + sum(arr, 0)
n == 0 => 0
Now we expand our steps:
sum(arr, 3)
== arr[2] + sum(arr, 2) // expand sum(arr,2) where n = 2
== arr[2] + arr[1] + sum(arr, 1) // expand sum(arr,1)
== arr[2] + arr[1] + arr[0] + sum(arr,0) // expand sum(arr,0)
== arr[2] + arr[1] + arr[0] + 0
== 30 + 20 + 10 + 0
Test with
function sum(arr, n) {
console.log(`calling sum(arr, ${n})`);
if(n<=0) {
console.log(`returning 0`);
return 0;
} else {
console.log(`calculating [sum(arr, ${n-1}) + ${arr[n-1]}]`);
let s = sum(arr, n-1);;
console.log(`returning [sum(arr, ${n-1}) + ${arr[n-1]}] = [${s} + ${arr[n-1]}]`);
return s + arr[n-1];
}
}
sum([10,20,30,40], 3);
The output will be:
calling sum(arr, 3)
calculating [sum(arr, 2) + 30]
calling sum(arr, 2)
calculating [sum(arr, 1) + 20]
calling sum(arr, 1)
calculating [sum(arr, 0) + 10]
calling sum(arr, 0)
returning 0
returning [sum(arr, 0) + 10] = [0 + 10]
returning [sum(arr, 1) + 20] = [10 + 20]
returning [sum(arr, 2) + 30] = [30 + 30]
Two other classic examples of simple recursive functions are factorial and fibonacci, because those two formulas itself are recursive. Multiplication could also be computed recursively, if you think as a * b being a + (a + ...) where a is added b times.
If you're trying to code those functions, there's a hint to code this last example:
5 * 10 is equal to 5 + 5 * 9, which is equal to 5 + 5 + 5 * 8 and so on.
sum([10,20,30,40], 3-1) Will call sum function again, think about it.
Recursive functions usually operate with a value that is immediately accesible and another value that they obtain by calling themselves until a base case is reached.
In this example, that accesible parameter is one of the numbers of an array and the operation is just a simple addition. The base case will be reached when the function's parameters satisfy the if condition.
Think of the different iterations that happen here to understand how the final result is gotten:
First iteration, sum([10,20,30,40], 3)
The if condition is not fulfilled because 3 (n) is greater than 0, so the else branch's code is executed.
We have sum([10,20,30,40], 2) + arr[2]. We don't know the result of the recursive call yet but we have the value of the number located in the third position of the array, that is 30 (arrays are usually considered to start from 0).
Second iteration, sum([10,20,30,40], 2)
Again, this is not the base case yet (if branch), so we have:
sum([10,20,30,40], 2-1) + arr[2-1] ->
sum([10,20,30,40], 1) + arr[1] ->
sum([10,20,30,40], 1) + 20
Third iteration, sum([10,20,30,40], 1)
At this point, we have 30 and 20 as "partial results". These numbers and the results of the remaining iterations will all be added up, because that's what the code in the else branch does, an addition.
sum([10,20,30,40], 1-1) + arr[1-1] ->
sum([10,20,30,40], 0) + arr[0] ->
sum([10,20,30,40], 0) + 10
Another partial result has been added: 10.
Forth and final iteration, sum([10,20,30,40], 0)
The base case is finally reached, the if branch's code is executed and the recursion stops right here because there isn't another call to the recursive function in this code. The result of sum([10,20,30,40], 0) is 0 because the code returns 0.
Now that we have reached the end of the recursion, we can retrace our steps.
• The result of the third iteration is sum([10,20,30,40], 0) + 10. We know this is 0 + 10 now, so 10.
• The result of the second iteration is sum([10,20,30,40], 1) + 20 = 10 + 20 = 30.
• And the result of the first call and the original call to the function is sum([10,20,30,40], 2) + 30 = 30 + 30 = 60.
Recursive functions are really tricky at first but once you understand this logic of partial results that are "accumulated" until the moment the base case is reached, they get easier. Just take your time.
Related
I'm new to programming and learning about javascript recursion. It's my 5th day with JavaScript and following an online course.
The problem is that I need to sum up first n numbers of entries (first 3 numbers in this case) in an array.
But I'm ending up with sum of all and that also I'm not sure about.
var theArray = [1, 3, 8, 5, 7];
function sum(arr, n) {
if (n <= 0) {
return 1;
} else {
return arr[n - 1] + sum(arr, n - 2);
//assuming n is arr.length and n-1 is hence arr.length-1
}
}
console.log(sum(theArray, 3));
What am I doing wrong?
I checked most people are solving such with reduce method or with for of loop. I didn't learn those yet in the curriculum. But I know 'for loop' but that's good if the numbers are in incremental order I guess. Please explain this problem in my level.
When implementing something recursively, it's a good idea to think about the base condition. It does look like that's where you started, but your logic is flawed. n is the number of elements you would like to sum together. So let's say you want to sum the first n=3 elements of the array [2,3,4,5,6] and get 9. Here are the iterations.
return arr[n-1] + sum(arr, n-1) // arr[2] + sum(arr, 2) === 4 + sum(arr, 2) === 4 + 5
return arr[n-1] + sum(arr, n-1) // arr[1] + sum(arr, 1) === 3 + sum(arr, 2) === 3 + 2
return arr[n-1] // arr[0] === 2 (base case when n is 1)
I didn't solve the problem for you since this is obviously a school exercise, but the point is that the base case and the recursive call that you have are both slightly off.
Array of undetermined length, find the largest sum possible for any 3 consecutive numbers.
[2,0,1,100,200,10,7,2, 300,2,1 0] here 100,200,10 = 310 is the correct answer. Here only the combination of these 3 numbers produces the largest sum.
[2,1,0,20,71 = 0+20+7 = 27 is the answer that you should return.
const findMax = (numberArray) => {
let first = 0;
let second = 1;
let third = 2;
let max = 0;
for(; third < numberArray.length; first++, second++, third++) {
if(max < (numberArray[first] + numberArray[second] + numberArray[third])) {
max = numberArray[first] + numberArray[second] + numberArray[third];
}
}
return max;
}
console.log('Max sum of three consecutive numbers in array ===> ',findMax([2, 0, 100, 200, 10, 7, 2, 300, 2, 10]));
I want to visually understand what happens when this recursive code is run. I don't understand how the end result is 9.
In my mind, the f(x - 1) will iterate until it returns 5, then you add 1 which equals 6.
let f = x => {
if (x === 0) {
return 5
}
return 1 + f(x - 1)
}
let y = f(4)
console.log(y)
Thank you for your time
You have the reasoning backwards. It isn't that one gets added once at the very end, one gets added after each resursive call returns. Think about this line:
return 1 + f(x - 1)
Once the recursive f call returns, one is added to that result. Then this recursive call returns, and one is added again. That keeps happening until the initial call returns.
Since one is added once per recursive call, and it will recurse four times, and the base case returns 5, this function ends up basically just calculating
1 + 1 + 1 + 1 + 5 == 9
You could take a level for an indention of a log and look which level has an input and return value.
function f(x, level = 0) {
console.log(level, '>>'.repeat(level + 1), x);
var v = x === 0
? 5
: 1 + f(x - 1, level + 1);
console.log(level, '<<'.repeat(level + 1), v);
return v;
}
console.log('result', f(4));
.as-console-wrapper { max-height: 100% !important; top: 0; }
I came across this example of a recursive function in a textbook. I can see there are other threads on this site that ask a question about this very example from Eloquent JavaScript but that user's difficulty in understanding the example was to do with not understanding how functions are invoked in general.
function findSolution(target){
function find(start, history){
if(start == target)
return history
else if(start > target)
return null
else
return find(start + 5, "(" + history + " + 5)") ||
find(start * 3, "(" + history + " * 3)")
}
return find(1, "1");
}
You supply a target number to the findSolution function, and it executes the inner function, find, which calls itself until it finds a way to reach the target number by adding 5 or multiplying by 3. Say I supply the number 13 as a target to reach. The parameters increment as follows.
Start = 1 + 5, History = "(1 + 5)"
Start = 6 + 5, History = "(1 + 5) + 5"
Start = 11 + 5, History = "(1 + 5) + 5) + 5"
Start becomes 16, and this is higher than 13, so this will return null. So the find function tries to multiply start by 3 instead of adding 5, going back to 11...
Start = 11 * 3, History = "(1 + 5) + 5) * 3"
This is also too high, and will so return null. Surely the function stops here, right??
When I test it out though, console logging the start values each time find recursively calls itself, it continues to call itself until it reaches number 13. The start values the function cycles through after 33 are:
18
3
8
13
But how is any of this possible? Shouldn't the function just return false after it reaches 16 and 33?
Console.log history just before the base case. That will help to understand how it works
There is a syntax error in your (the) example code. It should appear like this:
function findSolution(target){
function find(start, history){
if(start == target)
return history
else if(start > target)
return null
else
return (find(start + 5, "(" + history + " + 5)") ||
find(start * 3, "(" + history + " * 3)"))
}
return find(1, "1");
}
(Note the structure of the last return in the inner function.)
When running the updated function with an input of 13, I see this in the console:
(((1 * 3) + 5) + 5)
I am a little bit confused on the exact execution timeline in which the following function runs. I saw this code on the MDN guide:
function foo (i) {
if (i<0) return;
console.log('begin' + i);
foo(i-1);
console.log('end' + i);
}
Based on my knowledge of how functions work, this is what I thought, though my knowledge is inadequate:
I think when the function foo(3) is called, it will go to the function and check the condition if i < 0, then it will run the next code console.log('begin:' + i).
After that, the next line of code is executed, since JavaScript execute line by line, the next line of code which is foo(i-1) will be executed.
It takes the current value of i which is 3 minus 1, so foo(2) is called and the execution continues.
My question is: Is my understanding correct?. If no please explain what this code is doing, otherwise can anyone explain breiefly when will the function stop being called?
What happens when you call foo(3) is as follows (in pseudocode):
execute foo(3)
3 is greater than 0 thus log(begin 3)
execute foo(2)
2 is greater than 0 thus log(begin 2)
execute foo(1)
1 is greater than 0 thus log(begin 1)
execute foo(0)
0 is equal to 0 thus log(begin 0)
execute foo(-1)
-1 is less than 0 thus return
log(end 0)
log(end 1)
log(end 2)
log(end 3)
return
It works like this:
foo(3)->
if (3 < 0)
return
console.log('begin' + 3)
if (2 < 0)
return
console.log('begin' + 2)
if (1 < 0)
return
console.log('begin' + 1)
if (0 < 0)
return
console.log('begin' + 0)
if (-1 < 0)
return
console.log('end' + 0)
console.log('end' + 1)
console.log('end' + 2)
console.log('end' + 3)
I've been trying to write code that multiplies even indexed elements of an array by 2 and odd indexed elements by 3.
I have the following numbers stored in the variable number, which represents an array of numbers
numbers = [1,7,9,21,32,77];
Even Indexed Numbers - 1,9,32
Odd Indexed Numbers - 7, 21, 77
Please keep in mind that arrays are Zero Indexed, which means the numbering starts at 0. In which case, the 0-Indexed element is actually 1, and the 1-Indexed element is 7.
This is what I expected the output to be
[2,21,18,63,64,231]
Unfortunately, I got this output
[2,14,17,42,64,154]
Here is the code for my method
numbers = numbers.map(function(x) {
n = 0;
while (n < numbers.length) {
if (n % 2 == 0) {
return x * 2;
}
else {
return x * 3;
}
n++;
}});
return numbers;
Here I created a while loop, that executes code for every iteration of the variable n. For every value of the variable n, I'm checking if n is even, which is used by the code n % 2 == 0. While it's true that 0 % 2 == 0 it's not true that 1 % 2 == 0. I'm incrementing n at the end of the while loop, so I don't understand why I received the output I did.
Any help will be appreciated.
You created a global property called n, by doing
n = 0;
and then,
while (n < numbers.length) {
if (n % 2 == 0) {
return x * 2;
} else {
return x * 3;
}
}
n++; // Unreachable
you always return immediately. So the, n++ is never incremented. So, n remains 0 always and so all the elements are multiplied by 2 always.
The Array.prototype.map's callback function's, second parameter is the index itself. So, the correct way to use map is, like this
numbers.map(function(currentNumber, index) {
if (index % 2 === 0) {
return currentNumber * 2;
} else {
return currentNumber * 3;
}
});
The same can be written succinctly, with the ternary operator, like this
numbers.map(function(currentNumber, index) {
return currentNumber * (index % 2 === 0 ? 2 : 3);
});
To complement the other answer, the source of OP's confusion is on how "map" works. The map function is already called for each element - yet, OP attempted to use a while loop inside it, which is another way to iterate through each element. That is a double interaction, so, in essence, if OP's code worked, it would still be modifying each number n times! Usually, you just chose between a loop or map:
Using a loop:
var numbers = [1,7,9,21,32,77];
for (var i=0; i<numbers.length; ++i)
numbers[i] = i % 2 === 0 ? numbers[i] * 2 : numbers[i] * 3;
Using map:
var numbers = [1,7,9,21,32,77];
numbers.map(function(number, index){
return number * (index % 2 === 0 ? 2 : 3);
});
Or, very briefly:
[1,7,9,21,32,77].map(function(n,i){ return n * [2,3][i%2]; });
Basically you want to return a modified array that if the elements of the initial one is:
in even position, then multiply the element by 2.
in odd position, then multiply the element by 3.
You can use map with arrow functions and the conditional (ternary) operator to get this one-liner
console.log([1,7,9,21,32,77].map((num,ind) => num * (ind % 2 === 0 ? 2 : 3)));
This will output the desired
[2, 21, 18, 63, 64, 231]