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!"
Related
Here is an example of a string reverse function with recursion.
I'd like to understand why:
(1) If I switch the return line inner actions like this:
return word.charAt(0) + reversed(word.substring(1))
I get the string again but not reversed.
(2) Where the 'word.charAt()' letters are being saved through the nested calls (and overall if it's the same with a regular function), memory wise what I miss here, what keeps them accumulated with tact and where are they 'going'.
I'd like an explanation of some kind to how the memory concept works in js to understand better the relations as I code ( I think especially in and out of functions in my case).
var reverseArray = reversedItems(arr)
function reverseAll(items) {
return items.map(function reversed(word) {
if (word === "") return ""
return reversed(word.substring(1)) + word.charAt(0)
})
}
You should understand the reversed function separately before concerning yourself with reverseAll -
function reverse(word) {
if (word === "") return ""
return reverse(word.substring(1)) + word.charAt(0)
}
console.log(reverse("hello world"))
Starting with reverse("hello_world") we can easily trace the evaluation. Whenever the input word is non-empty, a new stack frame is opened with the recursive call to the sub-problem reverse(word.substring(1)). The ... + word.charAt(0) portion remains in the calling frame and only resumes after the descendant frame returns -
reverse("hello world") =
reverse("ello world") + "h" =
reverse("llo world") + "e" + "h" =
reverse("lo world") + "l" + "e" + "h" =
reverse("o world") + "l" + "l" + "e" + "h" =
reverse(" world") + "o" + "l" + "l" + "e" + "h" =
reverse("world") + " " + "o" + "l" + "l" + "e" + "h" =
reverse("orld") + "w" + " " + "o" + "l" + "l" + "e" + "h" =
reverse("rld") + "o" + "w" + " " + "o" + "l" + "l" + "e" + "h" =
reverse("ld") + "r" + "o" + "w" + " " + "o" + "l" + "l" + "e" + "h" =
reverse("d") + "l" + "r" + "o" + "w" + " " + "o" + "l" + "l" + "e" + "h" =
reverse("") + "d" + "l" + "r" + "o" + "w" + " " + "o" + "l" + "l" + "e" + "h" =
Here we meet the base case, recursion stops and empty string is returned. Now all of the open stack frames collapse, starting with the deepest frame returning its value to its caller -
"" + "d" + "l" + "r" + "o" + "w" + " " + "o" + "l" + "l" + "e" + "h" =
"d" + "l" + "r" + "o" + "w" + " " + "o" + "l" + "l" + "e" + "h" =
"dl" + "r" + "o" + "w" + " " + "o" + "l" + "l" + "e" + "h" =
"dlr" + "o" + "w" + " " + "o" + "l" + "l" + "e" + "h" =
"dlro" + "w" + " " + "o" + "l" + "l" + "e" + "h" =
"dlrow" + " " + "o" + "l" + "l" + "e" + "h" =
"dlrow " + "o" + "l" + "l" + "e" + "h" =
"dlrow o" + "l" + "l" + "e" + "h" =
"dlrow ol" + "l" + "e" + "h" =
"dlrow oll" + "e" + "h" =
"dlrow olle" + "h" =
And finally we can close the outermost call to reverse and return the result -
"dlrow olleh"
In this program, the stack is used to sequence operations and combine resulting values in the intended order. If the input word was significantly large, you would run into a stack overflow because too many frames would be opened and you essentially break the JavaScript runtime limit for such computations. Memory or heap is only used for all of the intermediate string allocations.
The ever-growing stack in the program above demonstrates a recursive process. This is characteristic of any recursive program that doesn't use a tail call. A tail call is simply the last call in your function, returned directly to its caller -
function reverse(word) {
function loop(r, w) {
if (w == "") return r
return loop(w[0] + r, w.substr(1)) // <- loop is the last called
}
return loop("", word)
}
console.log(reverse("hello world"))
This demonstrates a linear iterative process, so called because the process created by the recursive function stays flat and straight like a line -
reverse("hello world") =
loop("", "hello world") =
loop("h", "ello world") =
loop("eh", "llo world") =
loop("leh", "lo world") =
loop("lleh", "o world") =
loop("olleh", " world") =
loop(" olleh", "world") =
loop("w olleh", "orld") =
loop("ow olleh", "rld") =
loop("row olleh", "ld") =
loop("lrow olleh", "d") =
loop("dlrow olleh", "") =
"dlrow olleh"
Some languages have tail call optimization which means the recursive function like the one above would be safe from the stack overflow problem. The compiler or runtime effectively converts the recursive call into a loop -
function reverse(word) {
function loop(r, w) {
while (true) {
if (w == "") return r
r = w[0] + r
w = w.substr(1)
}
}
return loop("", word)
}
console.log(reverse("hello world"))
Above only 2 frames are used and memory allocations of 3 bindings, word, r and w. Memory allocations to compute + and w.substr(1) are also made and are recaptured by the runtime's automatic garbage collector.
In ECMAScript 6, tail call elimination was added to the specification however it is unsupported in almost every popular runtime and that is unlikely to change. That doesn't mean however we are constrained to writing recursive programs using imperative style while loops. There are various techniques to make recursive programs safe even in JavaScript, even in runtimes that do not support this optimization.
Consider this implementation of reverse using loop and recur -
const reverse = word =>
loop
( (r = "", w = word) =>
w == ""
? r
: recur(w[0] + r, w.substr(1))
)
The non-recursive loop and recur functions are generic and allow us to use them to write most recursive programs that will not cause a stack overflow -
const recur = (...values) =>
({ recur, values })
const loop = run =>
{ let r = run ()
while (r && r.recur === recur)
r = run (...r.values)
return r
}
console.log(reverse("hello world"))
This has a very similar performance profile to the while loop above. Only 2 stack frames and 3 bindings with an small overhead of some immediately garbage-collected values like +, substr and recur -
Expand the snippet below to verify the result in your own browser -
const recur = (...values) =>
({ recur, values })
const loop = run =>
{ let r = run ()
while (r && r.recur === recur)
r = run (...r.values)
return r
}
const reverse = word =>
loop
( (r = "", w = word) =>
w == ""
? r
: recur(w[0] + r, w.substr(1))
)
console.log(reverse("hello world"))
"dlrow olleh"
In fact, any recursive program, tail call or not, can be made stack-safe using various techniques. If this sort of thing sounds interesting to you, see this related Q&A for an in-depth exploration of the topic.
I am currently trying to complete an assignment for an intro2Javascript course. The question basically asks me to return a string of multiples of 2 parameters (num, numMultiple). Each time it increments the value i until i = numMultiple. For example:
5 x 1 = 5\n
5 x 2 = 10\n
5 x 3 = 15\n
5 x 4 = 20\n
This was my attempt:
function showMultiples(num, numMultiples) {
var result;
for (i = 1; i <= numMultiples; i++) {
result = num * i
multiples = "" + num + " x " + i + " = " + result + "\n"
return (multiples)
}
}
...and because the assignment comes with pre-written console logs:
console.log('showMultiples(2,8) returns: ' + showMultiples(2, 8));
console.log('showMultiples(3,2) returns: ' + showMultiples(3, 2));
console.log('showMultiples(5,4) returns: ' + showMultiples(5, 4));
console.log('\n');
This is my output:
showMultiples(2,8) returns: 2 x 1 = 2
Scratchpad/1:59:1
showMultiples(3,2) returns: 3 x 1 = 3
Scratchpad/1:60:1
showMultiples(5,4) returns: 5 x 1 = 5
UPDATE
You were doing two things incorrectly:
1) You were returning after the first iteration through your loop
2) You were assigning to multiples instead of appending to it.
Since you want to gather all the values and then show the final result first, I add all of the values to an array, and then use unshift() to add the final element (the result) to the beginning of the array. Then I use join() to return a string representation of the desired array.
function showMultiples(num, numMultiples) {
var result;
var multiples = [];
for (let i = 1; i <= numMultiples; i++) {
result = num * i
multiples.push("" + num + " x " + i + " = " + result + "\n")
}
multiples.unshift(multiples[multiples.length-1]);
return (multiples.join(''))
}
console.log('showMultiples(2,8) returns: ' + showMultiples(2, 8));
console.log('showMultiples(3,2) returns: ' + showMultiples(3, 2));
console.log('showMultiples(5,4) returns: ' + showMultiples(5, 4));
console.log('\n');
You need to declare all variables, because without you get global variables (beside that it does not work in 'strict mode').
The second point is to use multiples with an empty string for collecting all intermediate results and return that value at the end of the function.
For keeping the last result, you could use another variable and append that value at the end for return.
function showMultiples(num, numMultiples) {
var i,
result,
multiples = "",
temp = '';
for (i = 1; i <= numMultiples; i++) {
result = num * i;
temp = num + " x " + i + " = " + result + "\n";
multiples += temp;
}
return temp + multiples;
}
console.log('showMultiples(2,8) returns: ' + showMultiples(2, 8));
console.log('showMultiples(3,2) returns: ' + showMultiples(3, 2));
console.log('showMultiples(5,4) returns: ' + showMultiples(5, 4));
As other answers say, your problem is in multiple.
You are clearing multiple every iteration and storing the new value, but you do not want that, you want to add the new result, and to do so you use this code:
multiples = multiple + "" + num + " x " + i + " = " + result + "\n"
which can be compressed in what the rest of the people answered:
multiples += "" + num + " x " + i + " = " + result + "\n"
Probably you already know, but to ensure:
a += b ---> a = a + b
a -= b ---> a = a - b
a *= b ---> a = a * b
and there are even more.
I am not good at algorithm analysis. The source code is from this place: https://repl.it/KREy/4
Instead of dynamic programming, this piece of code uses a cache to optimize the BigO by sacrificing memory. However, I just don't know how to calculate the BigO mathematically after this cache mechanism is added. May anyone genius give an explanation?
To ease reading I will copy and paste them in the following space:
// using cache to optimize the solution 1 from http://www.techiedelight.com/longest-palindromic-subsequence-using-dynamic-programming/
const cache = {};
var runningtime = 0;
var runningtimeWithCache = 0;
function computeGetLP(x, start, end){
const answer = a => {
runningtime++;
return a;
}
console.log("try to compute: " + x + " " + start + " " + end + " ");
if(start > end)
return answer(0);
if(start == end)
return answer(1);
if(x[start] == x[end])
return answer(2 + computeGetLP(x, start+1, end-1));
return answer(Math.max(computeGetLP(x, start+1, end),
computeGetLP(x, start, end-1)));
}
function computeGetLPWithCache(x, start, end){
const answer = a => {
runningtimeWithCache ++;
console.log("do cache: " + x + " " + start + " " + end + " is " + a);
cache["" + x + start + end] = a;
return a;
}
console.log("try to compute: " + x + " " + start + " " + end + " ");
if(cache["" + x + start + end]){
console.log("hit cache " + x + " " + start + " " + end + " "+ ": ",cache["" + x + start + end]);
return cache["" + x + start + end];
}
if(start > end)
return answer(0);
if(start == end)
return answer(1);
if(x[start] == x[end])
return answer(2 + computeGetLPWithCache(x, start+1, end-1));
return answer(Math.max(computeGetLPWithCache(x, start+1, end),
computeGetLPWithCache(x, start, end-1)));
}
const findLongestPadlindrom1 = s => computeGetLPWithCache(s, 0, s.length-1)
const findLongestPadlindrom2 = s => computeGetLP(s, 0, s.length-1)
const log = (function(){
var lg = [];
var output = function(text){
lg.push(text);
}
output.getRecord = function(){
return lg;
}
return output;
})();
log("Now let's do it with cache")
log("result: "+findLongestPadlindrom1("ABBDCACB"))
log("running time is: " + runningtimeWithCache)
log("Now let's do it without cache")
log("result: "+findLongestPadlindrom2("ABBDCACB"))
log("running time is: " + runningtime)
log.getRecord();
I'm not an expert in algorithms either, but I remember cache techniques like this from Introduction to Algorithms, chapter 15, just beside Dynamic Programming. It has the same big O to DP, which is O(n^2) in your case.
Each call to computeGetLPWithCache() costs O(1) for it does not contain loops. Consider the worst case where x[start] != x[end] in each recursion. How many times are we going to call computeGetLPWithCache()?
Let n = length(x), [start, end] represent a call to computeGetLPWithCache(x, start, end), and F(n) equals the number of calls. In computeGetLPWithCache(x, 0, n), 2 sub calls - [0, n-1] and [1, n] - are issued. The former costs F(n), and when we're doing the latter, we discover that in each iteration, the first call's [start, end] range is a true subset of [0, n-1] whose result is already written to cache during the [0, n-1] call, thus no need for recursing. Only the second call which has the element n in it has to be calculated; there're n such calls [1,n][2,n][3,n]...[n,n] (one in each stack layer), so F(n+1) = F(n) + O(n).
F(n) = F(n-1) + O(n-1) = F(n-2) + O(n-2) + O(n-1) = ... = O(1+2+...+(n-1)) = O(n^2).
Hope I've got the meaning through. Replies are welcome.
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)
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