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)
Related
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 was working on leetcode question and come across this question and saw an answer online.
According the MDN, we should an inner function sort(function(a,b) return a + b) to sort an array properly.
Can someone explain how does the closure works and further explain the following codes?
(I don't quite understanding the sequence of how the comparison is done)
/*Given a list of non negative integers, arrange them such that they form the largest number.
For example, given [3, 30, 34, 5, 9], the largest formed number is 9534330.
Note: The result may be very large, so you need to return a string instead of an integer.*/
var largestNumber = function(nums) {
return nums.sort(function (a,b){
return (b + '' + a) - (a + '' + b);
}).join('').replace(/^0*/,'') || '0';
};
var nums= [3, 30, 34, 5, 9]
console.log(largestNumber(nums));
What this sort is basically doing is for each element in the array a and b. Check which way the numbers would be high based on how they would be ordered. For example, if a = 30 and b = 5. Then:
(b + '' + a) - (a + '' + b)
530 - 305
225
Since this is a positive number it means b would be the left of of a in the final array (string).
So notice that in the example data [3, 30, 34, 5, 9], the element 9 compared to any other element would result in 9 being on the left (meaning it's the lowest item in the array). Here is a snippet example of each comparison done with some extra console information (to show how each comparison is being done and the result, notice that 9 was always lower compared to each element. Then the next number 5 is lower than everything but 9):
var largestNumber = function(nums) {
return nums.sort(function (a,b){
var priority = (b + '' + a) - (a + '' + b)
console.log((b + '' + a) + " - " + (a + '' + b) + " => " + (priority));
if(priority > 0) console.log(a + " > " + b);
else console.log(a + " < " + b);
return (b + '' + a) - (a + '' + b);
}).join('').replace(/^0*/,'') || '0';
};
var nums= [3, 30, 34, 5, 9]
console.log(largestNumber(nums));
The snipped you presented is basically a code that builds the largest possible "number" out of the elements of an array.
Lets imagine we have the following input: [3, 30, 34, 5, 9]
First of all, the sort is taking a function as parameter. Its job is to sort the nums in descending lexicographic order (so a 34 would be lesser than a 5, because 3 is lesser than 5). It does that by comparing the values of the strings composed by the "ab" and "ba", so if "ba" - "ab" is a negative value, it will assume that 'a' is lesser than 'b', and so on.
At this step you have: [9,5,34,3,30]
After the sorting takes place, it invokes the join() function with '' as parameter, which means it will join the elements into a string, separating each element with the given paramenter, which is no separation at all.
At this step you have: "9534330"
Then, you have a call to the replace function, which will look for a certain pattern and replace it by the given second parameter. The first parameter in this case is a regular expression, which will match each string with '0' at the beginning of it and that contain zero or more occurences of '0'.
(Reference to Regular expressions: http://www.w3schools.com/js/js_regexp.asp)
At this step you still have: "9534330"
Finally, at the end of the return expression there is an || '0', which basically means that it will return '0' in case the first part of the return expression is false, either by wrong or missing input.
This question already has answers here:
How does Eloquent JavaScript recursion example terminate as return 1 but still output exponential value
(2 answers)
Closed 7 years ago.
From page 50 of Haverbeke's second edition. I added a couple of console.log to try to better track the progress.
function power(base, exponent) {
if (exponent == 0) {
console.log("line 5 " + base + " " + exponent);
return 1;
}
else
console.log("line 10 " + base + " " + exponent);
return base * power(base, exponent -1);
}
console.log(power(2,3));
// Output
line 10 2 3
line 10 2 2
line 10 2 1
line 5 2 0
8
//
I expect the final output to be 1 since when the if (exponent == 0) is true, the next statement is return 1;, but it appears to enter the else one more time to return 8. But shouldn't the return kick us out of the function.
Obviously a newbie or wouldn't be stuck on page 50 of a supposedly beginner book.
Thanks for any help.
Whenever the function enters the "else" branch, a new stack frame is created, waiting for the result of the recursive call. You can imagine the evaluation step by step:
power(2, 3) enters the else branch, and it returns base * power(base, exponent - 1).
2 * power (2, 2) enters the else branch, and it returns base * power(base, exponent - 1).
2 * (2 * power (2, 1)) enters the else branch, and it returns base * power(base, exponent - 1).
2 * (2 * (2 * power (2, 0))) enters the if branch, and it returns 1.
You can finally evaluate the result: 2 * (2 * (2 * 1)), which is 8.
The end result of the function call power(2,3) is not the last return, but the combination of returned values, by the subsequent internal function calls. Let's deconstruct the recursive function:
power(2,3) returns 2 * power(2,2)
power(2,2) returns 2 * power(2,1)
power(2,1) returns 2 * power(2,0)
power(2,0) returns 1
So in total, power(2,3) returns 2 * 2 * 2 * 1 which is equal to 8.
The return statement exits from one invocation of the function. In order to get to the return 1; line, the function will have been called several times (based on the original value of the exponent).
The first invocation is
console.log(power(2,3));
Inside the function, subsequent invocations take place here:
return base * power(base, exponent -1);
Each one will correspond with a return.
Oh, and as #TJCrowder notes in a comment, that code is not correct: the else part should be wrapped in { }:
if (exponent == 0) {
console.log("line 5 " + base + " " + exponent);
return 1;
}
else {
console.log("line 10 " + base + " " + exponent);
return base * power(base, exponent -1);
}
I'm assuming that the missing { } wrapper was a transcription error.
the question is pretty similar to this thread Javascript..totally lost in this tutorial.
function findSequence(goal) {
function find(start, history) {
if (start == goal)
return history;
else if (start > goal)
return null;
else
return find(start + 5, "(" + history + " + 5)") ||
find(start * 3, "(" + history + " * 3)");
}
return find(1, "1");
}
print(findSequence(24));
I got stuck at this part :
find(start * 3, "(" + history + " * 3)");
each time start goes beyond goal what does it do? it says it return null but when I test and put breakpoint on
if (start == goal) it shoes this on the console
history: "(((((1 + 5) + 5) + 5) + 5) + 5)"
start: 26
history: "(((((1 + 5) + 5) + 5) + 5) * 3)"
start: 63
it add up *3 and take off +5, I don't understand how.
The return statement:
return find(start + 5, "(" + history + " + 5)") ||
find(start * 3, "(" + history + " * 3)");
is an expression involving the "||" operator. That operator will cause the left-hand side to be evaluated. If the result of that is not null, zero, false, or the empty string, then that value will be returned. If it is one of those "falsy" values, then the second expression is evaluated and returned.
In other words, that could be re-written like this:
var plusFive = find(start + 5, "(" + history + " + 5)");
if (plusFive !== null)
return plusFive;
return find(start * 3, "(" + history + " * 3)")
If "start" ever exceeds "goal", the function returns null. Of course, if both the alternatives don't work, then the whole thing will return null.
The expression:
find(start + 5, "(" + history + " + 5)") ||
find(start * 3, "(" + history + " * 3)")
Will first attempt to evaluate:
find(start + 5, "(" + history + " + 5)")
If the returned value is not null, 0, false, or the empty string then the statement evaluates to the returned value.
If the returned value is null, 0, false, or the empty string then the following will be evaluated next:
find(start * 3, "(" + history + " * 3)")
If the returned value is not null, 0, false, or the empty string, then the statement evaluates to the returned value.
If the returned value is null, 0, false, or the empty string, then the statement evaluates to null, 0, false, or the empty string (whichever was returned by the *3 function call).
So the line:
return find(start + 5, "(" + history + " + 5)") ||
find(start * 3, "(" + history + " * 3)")
is like saying "I'm going to try to find the solution by guessing that I add 5 at this step, and if that doesn't work I'll try to multiply by 3 at this step, and if that doesn't work I give up!"
My introductory tutorial has suddenly become very advanced. I have no idea how this program works. Can you explain in plain language?
At the end it prints (((1 * 3) + 5) * 3), but I don't get it at all. I understand that findSequence gets passed 24, that triggers function find. I'm assuming that function find gets passed 1,"1" with the latter being assigned to history?? but I don`t understand why the second 1 is in quotation marks "1!, nor do I understand the use of quotation marks when it returns find(start etc.
function findSequence(goal) {
function find(start, history) {
if (start == goal)
return history;
else if (start > goal)
return null;
else
return find(start + 5, "(" + history + " + 5)") ||
find(start * 3, "(" + history + " * 3)");
}
return find(1, "1");
}
print(findSequence(24));
You have an "output" string (((1 * 3) + 5) * 3), a goal 24 and a first character 1. The 1 is the 1 in 1 * 3. This program will assemble a string containing a math expression, adding (), *3 and +5 to try to obtain the goal. The two parameters of the find function are the current total and the expression that will generate the total. Clearly the expression is a string. The find compares the current total to the goal, and if it's equal then the expression is correct and it returns it, if the current total is > of the goal then he failed and return null. Otherwhise he add some operations to the expression. He tries two "ways", one multiplying * 3 the current result, the other adding +5 to the current result. It's recursive on a tree (so each time he will bifurcate in two recursive calls). null || something == something, so the branch that will find a response will return his response, the other branch will return null and the "winning" response will be passed back.
Let's say the goal is 11.
find(1, "1")
compares 1 with 11 and calls: (2.) find(1 + 5, "(" + "1" + " + 5)") (so find(6, "(1 + 5)") and (3.) find(1 * 3, "(" + "1" + " * 3)") (so find(3, "(1 * 3)")
compares 6 with 11 and calls (4.) find (6 + 5, "(" + "(1 + 5)" + " + 5)") (so finds(11, "((1 + 5) + 5)") and (5.) find (6 * 3, "(" + "(1 + 5)" + " * 3)" (so find(18, "((1 + 5) * 3)"
compares 3 with 11 and calls (6.) find (3 + 5, "(" + "(1 * 3)" + " + 5)") (so finds(8, "((1 * 3) + 5)") and (7.) find (3 * 3, "(" + "(1 * 3)" + " * 3)" (so find(8, "((1 + 3) * 3)"
compares 11 with 11. The numbers are equal. So he returns "((1 + 5) + 5)" (the history). 5, 6, 7 will at a certain point go "overboard" and surpass the 11, so they'll return null. null || null == null, "((1 + 5) + 5)" || null == "((1 + 5) + 5)", so the history will win against the nulls and it will be returned.
To make it even clearer, try these versions:
function findSequence(goal) {
function find(start, history) {
if (start == goal)
return history;
else if (start > goal)
return null;
else {
var ret = find(start + 5, "(" + history + " + 5)");
if (ret == null)
ret = find(start * 3, "(" + history + " * 3)");
return ret;
}
}
return find(1, "1");
}
print(findSequence(24));
And this, where instead of an expression you'll get only as tring of + and *
function findSequence(goal) {
function find(start, history) {
if (start == goal)
return history;
else if (start > goal)
return null;
else {
var ret = find(start + 5, history + "+");
if (ret == null)
ret = find(start * 3, history + "*");
return ret;
}
}
return find(1, "1");
}
print(findSequence(24));
And be aware that, as an example, it's quite complex because it used closures (locally defined functions).
Try this tutorial out
http://nicksjavascript.blogspot.com
its made for beginners