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.
I am trying to write a simple program to find the greatest prime factor of an integer in JavaScript. The code I have written to do this follows:
let ans;
function factor(target, half) {
for (let i = 2; i < half; i++) {
if (target % i == 0) {
ans = target / i;
factor(ans, ans / 2);
}
}
}
factor(30, 15);
console.log(ans);
Now whether or not this code is an efficient solution to the problem or if it even works at all is beyond my issue with it: When I follow breakpoints set at each line of the factor function, I see that right after i = 2, target = 5, half = 2.5, and ans = 5, the value of target and half jump back up to 15 and 7.5 respectively. However, I do not see where in my code the values are told to change.
You're calling the function recursively, and each call to the function gets its own target, half, and i variables. In the first call to factor, target is 30 and half is 15. Then you call it again with the arguments 15 and 7.5; that inner call to factor gets its own target (15) and half (7.5), but the outer call still has its copies (30) and (15). This continues when you call factor again recursively, creating a third set, etc. When you step out of the innermost call, its variables disappear and you see the ones that are for the call that called it.
It may be clearer with a simpler example:
function countdown(value, indent) {
var twice = value * 2;
console.log(indent + "[before] value = " + value + ", twice = " + twice);
if (value > 0) {
countdown(value - 1, indent + " ");
}
console.log(indent + "[after] value = " + value + ", twice = " + twice);
}
countdown(3, "");
.as-console-wrapper {
max-height: 100% !important;
}
The output of that is:
[before] value = 3, twice = 6
[before] value = 2, twice = 4
[before] value = 1, twice = 2
[before] value = 0, twice = 0
[after] value = 0, twice = 0
[after] value = 1, twice = 2
[after] value = 2, twice = 4
[after] value = 3, twice = 6
As you can see, the values for value and twice in the outer call aren't changed by making the inner call. Each call gets its own set of variables.
why is it necessary to add return statement before ternary operator in recursive function to return function output?
// This dose not work
function rec(n) {
n == 1 ? n : n + rec(n - 1);
}
// This works as return statement is added before ternary operator
function rec(n) {
return n == 1 ? n : n + rec(n - 1);
}
// This works
function rec(n) {
if (n == 1) return 1;
return n + rec(n - 1);
}
// If you would like to do this in one line then correct solution would be:
let rec = n => n == 1 ? n : n + rec(n - 1);
// Now you dont need to add the return keyword before
// This works as return statement is added before ternary operator
function rec(n) {
return n == 1 ? n : n + rec(n - 1);
}
// This works
function rec(n) {
if (n == 1) return 1;
return n + rec(n - 1);
}
A recursive function is function which calls itself during the execution. The ternary operator decides if the function need to call itself. So the return statement call the same function.
In the example n == 1 ? n : n + rec(n - 1); if n=1 then the function should return the value of n if not then the function will call itself with new value that is n-1.
You need a return because of
n + rec(n - 1);
where the rec(n-1) call needs to return a value to be able to calculate n + rec(n - 1), and that goes for each call to rec() until n reaches 1 when it just returns 1.
return is never default in ternary operation.
return is default in Arrow-function but it not default in normal function deceleration.
to return a output from a normal function execution it is always necessary to add return statement, but it is optional in case of Arrow-function.
function x() { 5;}
console.log(x()); // Opuput: undefined
let y = () => 5;
console.log(y()); // Output: 5
A conditional expression (often called a ternary) is simply an expression. It yields a value, but it doesn't do anything with it. In fact, unless it has side-effects, it's totally useless unless you either:
return it from a function,
assign its result to a variable, or
nest it in another expression in which you do one of these things
You may be confused by the fact that arrow functions with single-expression bodies return the result of that expression. It's still being returned by the function, even though you don't explicitly use return. And because of this simplicity, conditional expressions are often used as the body of arrow function.
But it should be no more surpising that you have to have return here than that you have to have it in
function add (x, y) {
return x + y;
}
If you took out the return there, the addition will still happen when the function is invoked, but it won't yield any value. It's the same thing in your original.
var levelOrder = function(root) {
const arr = [];
function traverse(node, level) {
if (!node) return;
if(arr[level] === undefined) {
arr[level] = [];
arr[level].push(node.val)
} else {
arr[level].push(node.val)
}
traverse(node.left, level + 1);
traverse(node.right, level + 1);
}
traverse(root, 0);
return arr;
};
In the recursion call to traverse function. Using
traverse(node.left, level + 1);
gives me the correct answer but
traverse(node.left, ++level);
gives me incorrect answer.
Let's say level is currently 0. My hypothesis is that the first example will feed 1 as the second argument to the traverse function. Second example will assign 1 to level (level = level + 1) and feed level(which is 1) as the second argument to the traverse function.
Lets assume level = 5;
level + 1 is an expression that returns the value 6 and doesn't change the value of level at all, so its value is still 5.
++level is an expression that increments that value of level to 6 and then returns the value of level which is now 6.
Twice in a row like in your function:
level + 1; // returns 6
level + 1; // returns 6
And now the other way:
++level; // returns 6
++level; // returns 7
That's why it's failing.
Should add all the natural numbers below 1000 that are multiples of 3 or 5.
var sum = _.reduce( _.range(1, 1000), function(x, n) {
if (n % 3 == 0 || n % 5 == 0) { return x+=n; }
}, 0);
I expect the output to be 233168 but I get NaN.
For some reason sum is not accepting the initialized value of 0. However if I preface this with var sum = 0; then it works and returns the proper output of 233168
Why doesn't it accept the initialized value?
The problem is the reducing function returns undefined when the conditional fails .. thus x evaluates to undefined (the last return value) in the subsequent invocation .. and undefined + a number is .. well, NaN.
Also, reduce is being used incorrectly; it should carry its own state. Compare it with:
var sum = _.reduce( _.range(1, 1000), function(x, n) {
// Add n to the tally if it is a valid multiple..
// (the returned value is used as the *next* value of x)
if (n % 3 == 0 || n % 5 == 0) { return x + n; }
// ..or simply return the current tally.
else { return x; }
}, 0);
Note that the sum variable was not assigned from within the reducing function (it would have been overwritten by the outside assignment anyway). This keeps reduce a pure operation, not withstanding the occasional abuse of a mutable memo, truer to its functional roots.