我认为我已经掌握了Javascript中的递归,但我很欣赏一些特定的递归代码,我会在一本书中阅读
根据我的理解,下面的代码正在执行几个步骤,如果您能够纠正我的理解中的任何错误,我会解释,我会非常感激:
findSolution功能正在为您寻找解决方案 加5或乘以3得到24
函数find是递归发生的地方
解决方案,声明if (start == target)
是告诉我的
递归结束时找到解决方案并返回历史记录
怎么会发生这种情况
第8-9行的return语句以(1 + 5)开头,等于6, 所以然后它开始回到顶部继续通过if 不满足的陈述然后进入return语句 再次这次(6 + 5)等于11
它将继续执行此操作,直到满足其中一个if语句。什么时候 start高于目标函数然后进入the ||的另一面声明并以(1 * 3)开头 历史等同于"(1 * 3)"
我不确定的是为什么函数继续通过第一部分在下一次迭代中将(5 *)加到5(1 * 3),函数如何知道添加5然后在下一次迭代中乘以3?为什么它不会继续添加5然后再这样做,直到它太大并返回null?
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");
}
console.log(findSolution(24));
// → (((1 * 3) + 5) * 3)
答案 0 :(得分:1)
它确实经历了你提到的每一种可能的情况。它确实继续添加5,直到它太大并返回null(在这种情况下为find(start + 5, "(" + history + " + 5)") === null (false)
,因此结果将来自另一个分支。
这很难解释为什么你需要了解执行堆栈或者可能会绘制一个执行树。 让我知道我该如何帮助
答案 1 :(得分:1)
也许这会让事情更清楚。
我刚刚在depth
- 函数中添加了find
- 参数来确定递归深度,并在console.log()
中记录所有递归调用。
function findSolution(target) {
//added a depth-property to show the recursion better
function find(start, history, depth) {
//simply log all calls in order
console.log("%s%d == %s", "| ".repeat(depth), start, history);
if (start == target)
return history;
else if (start > target)
return null;
else
return find(start + 5, "(" + history + " + 5)", depth+1) ||
find(start * 3, "(" + history + " * 3)", depth+1);
}
return find(1, "1", 0);
}
console.log(findSolution(24));

答案 2 :(得分:0)
以下是您的代码版本,它将为您打印一个执行树,以便您可以跟随该算法的所有不同排列,实际上,尝试:
function findSolution(target) {
function find(start, history, trace) {
trace.push(history)
if (start == target) {
console.log(trace.join(' => ') + ' => ' + start + ' == ' + target);
return history;
}
if (start > target) {
console.log(trace.join(' => ') + ' => ' + start + ' > ' + target);
return null;
}
return find(start + 5, "(" + history + " + 5)", [].slice.call(trace)) ||
find(start * 3, "(" + history + " * 3)", [].slice.call(trace));
}
return find(1, "1", []);
}
findSolution(24)
这是执行树:
1 => (1 + 5) => ((1 + 5) + 5) => (((1 + 5) + 5) + 5) => ((((1 + 5) + 5) + 5) + 5) => (((((1 + 5) + 5) + 5) + 5) + 5) => 26 > 24
1 => (1 + 5) => ((1 + 5) + 5) => (((1 + 5) + 5) + 5) => ((((1 + 5) + 5) + 5) + 5) => (((((1 + 5) + 5) + 5) + 5) * 3) => 63 > 24
1 => (1 + 5) => ((1 + 5) + 5) => (((1 + 5) + 5) + 5) => ((((1 + 5) + 5) + 5) * 3) => 48 > 24
1 => (1 + 5) => ((1 + 5) + 5) => (((1 + 5) + 5) * 3) => 33 > 24
1 => (1 + 5) => ((1 + 5) * 3) => (((1 + 5) * 3) + 5) => ((((1 + 5) * 3) + 5) + 5) => 28 > 24
1 => (1 + 5) => ((1 + 5) * 3) => (((1 + 5) * 3) + 5) => ((((1 + 5) * 3) + 5) * 3) => 69 > 24
1 => (1 + 5) => ((1 + 5) * 3) => (((1 + 5) * 3) * 3) => 54 > 24
1 => (1 * 3) => ((1 * 3) + 5) => (((1 * 3) + 5) + 5) => ((((1 * 3) + 5) + 5) + 5) => (((((1 * 3) + 5) + 5) + 5) + 5) => ((((((1 * 3) + 5) + 5) + 5) + 5) + 5) => 28 > 24
1 => (1 * 3) => ((1 * 3) + 5) => (((1 * 3) + 5) + 5) => ((((1 * 3) + 5) + 5) + 5) => (((((1 * 3) + 5) + 5) + 5) + 5) => ((((((1 * 3) + 5) + 5) + 5) + 5) * 3) => 69 > 24
1 => (1 * 3) => ((1 * 3) + 5) => (((1 * 3) + 5) + 5) => ((((1 * 3) + 5) + 5) + 5) => (((((1 * 3) + 5) + 5) + 5) * 3) => 54 > 24
1 => (1 * 3) => ((1 * 3) + 5) => (((1 * 3) + 5) + 5) => ((((1 * 3) + 5) + 5) * 3) => 39 > 24
1 => (1 * 3) => ((1 * 3) + 5) => (((1 * 3) + 5) * 3) => 24 == 24
答案 3 :(得分:0)
首先,函数find
以1.内部查找:
3
或添加5
s将无法使用它。 5
开始两个分支,另一个乘以3
。 / LI>
第一次发现的调用是1
的结果和"1"
的历史记录。
在第一个find
内部测试(start == target
)将失败,因为(1!= 24),第二个测试(start > target
)也将失败,因为(1 <= 24 )。所以我们执行else
内的内容。所以我们调用find会得到(1 + 5
)的结果和("( 1 + 5)"
)的历史记录,然后检查我们是否有一个历史记录让我们到24
(返回值不会是null
),或者如果返回的值为null
,则调用另一个查找结果为(1 * 3)
)和历史记录("( 1 * 3 "
),我们检查我们是否得到了与null
(正确答案)不同的返回值(没有答案)。
最好是由具有所有可能调用的树视图表示:
[1] -> [1 + 5] -> [6 + 5] -> [11 + 5] -> [16 + 5] -> [21 + 5] >> branch terminated (26 > 24)
| | | | -> [21 * 3] >> branch terminated (63 > 24)
| | | -> [16 * 3] >> branch terminated (48 > 24)
| | -> [11 * 3] >> branch terminated (33 > 24)
| -> [6 * 3] >> returns the right result (24 == 24)
|
|
| We will never have the next branch because we already got a result.
-> [1 * 3] -> [3 + 5] -> [8 + 5] -> [13 + 5] -> [18 + 5] -> [23 + 5] >> branch would have been terminated (28 > 24)
| | | | -> [23 * 3] >> branch would have been terminated (69 > 24)
| | | -> [18 * 3] >> branch would have been terminated (54 > 24)
| | -> [13 * 3] >> branch would have been terminated (39 > 24)
| -> [8 * 3] >> would have been a correct answer if we haven't already got one
-> [3 * 3] -> [9 + 5] -> [14 + 5] -> [19 + 5] >> would have been a correct answer if we haven't already got one
| | -> [19 * 3] >> terminated ...
| -> [14 * 3] >> terminated ...
-> [9 * 3] >> terminated ...
已终止的分支意味着条件(start > target
)已满足,因此返回null
给调用者将产生3种可能的结果:
find
且返回find
的{{1}}是null
中的第一个find
,那么我们称之为{{1}分支。find(start + 5, "(" + history + " + 5)") || find(start * 3, "(" + history + " * 3)")
而且返回* 3
的{{1}}是find
中的第二个find
,那么我们会返回null
这将终止父赎罪(这个find
)。find(start + 5, "(" + history + " + 5)") || find(start * 3, "(" + history + " * 3)")
,那么仅使用null
和find
组合就无法实现目标。返回正确答案的findSolution
(换句话说,满足条件+ 5
的{{1}})将阻止创建更多分支(它将返回非{{1}结果将由其调用者及其调用者返回...一直到* 3
)所以如果我们在find
中的第一个find
,那么第二个将永远不会被执行。