我感觉很接近解决这个问题,但是我不太理解这个功能。
我了解了函数如何继续检查目标数字,如果目标数字过高,它将返回null并返回第二个“ ||”应用运算符。
我不明白的是,一旦当前变量高于目标变量,它将开始返回历史变量,但没有附加值(+5)。这是怎么从字符串中取出的?????
任何解释将不胜感激。希望这是有道理的。我是从Marijn Haverbeke的《雄辩的Java语言》一书中摘录的
function findSolution(target) {
function find(current, history) {
if (current == target) {
return history;
} else if (current > target) {
//console.log(`CURRENT AT NULL: ` + current);
console.log(`HISTORY AT NULL: ${history}`);
return null;
} else {
console.log(`${history}`);
return find(current + 5, `(${history} + 5)`) ||
find(current * 3, `(${history} * 3)`);
}
}
return find(1, "1");
}
console.log(findSolution(24));
// → (((1 * 3) + 5) * 3)
答案 0 :(得分:1)
您正在通过递归进行深度优先搜索。每个人都在递归上有所不同。最终将使它为您点击。
我想在您的代码中做几个注释,以帮助它们打印出更自然的文字记录。希望这会有所帮助。
但是我认为最重要的是可视化您在递归中有多少个缩进层次。当您在递归深度优先搜索期间进行记录时,基本上就是在制作一棵二叉树,其输出类似于:
Root
Root > Left
Root > Right
它开始像这样递归嵌套:
Root
Root > Left
Root > Left > Left
Root > Left > Right
Root > Right
Root > Right > Left
Root > Right > Right
您将创建探索的“ +5”和“ * 3”分支,而不是“左”和“右”路径。在递归中,首先探索树的+5分支以寻找解决方案。如果找不到,则探索树的* 3分支。如果什么都没找到,那仅意味着答案并不在您正在考虑的分支上,而必须在树的前面进行其他选择。
当尝试两种方法都没有成功时,似乎会发生一些回溯。但是,实际上,这只是一个假设的结论,我们说“如果我们+5,我们能到达那里吗?”或“我们能到达那里* 3吗?”如果对两者的回答都是“否”,那么您将无法从自己所在的位置到达那里。您不必真正回溯,递归的好处在于您可以在搜索中找到所需的位置,因为有人将您作为“如果...的假设”的一部分来调用您。如果您的整个搜索为空,则没有问题。您只需放弃搜索的当前分支,而调用的“某人”将在其他分支上尝试其他操作。
您的递归状态(您正在探索的分支)保留在您的调用堆栈中。那就是我们实际上“备份”的地方。
history
从未修改。我们只是探讨通过递归构造的history
的不同版本。每个history
是其自己的副本,并且只会变长(在搜索树中的左或右分支)或被放弃,并且从递归中其他位置的其他history
继续搜索。
因此,这是您的代码,其中包含缩进和一些冗长的描述,说明每个步骤所发生的情况,希望可以更紧密地与递归联系起来。
function spaces(indent) {
return ' '.repeat(indent);
}
function findSolution(target) {
function nope(indent, history) {
console.log(spaces(indent) + `Sadly we've exhausted all possible ways of getting there from this starting point. We may still be able to get to ${target}, but not by starting from ${history}.`);
return false;
}
function badnews(history) {
console.log(`I've tried everything and there's just no way of getting to ${target}. :(`);
return false;
}
function find(current, which, history, indent) {
if (current == target) {
console.log(spaces(indent) + `${which}, and guess what...we finally found a solution! Because ${history} = ${current}. So we can stop now. :)`);
return history;
} else if (current > target) {
//console.log(`CURRENT AT NULL: ` + current);
console.log(spaces(indent) + `${which}, we reached a dead end because ${history} = ${current} which is unfortunately already bigger than ${target}.`);
return null;
} else {
console.log(spaces(indent) + `${which}, ${history} looks promising because it equals ${current}, which is still less than ${target}. We'll try two ways of getting to ${target} from here.`);
return find(current + 5, 'First, by adding 5', `(${history} + 5)`, indent+1) ||
find(current * 3, 'Second, by multiplying by 3', `(${history} * 3)`, indent+1) ||
nope(indent+1, history);
}
}
return find(1, 'Initially', "1", 0) || badnews();
}
console.log(`${findSolution(24)}`);
为防万一,输出复制到下面。抱歉,没有压缩输出,因为缩进更为重要,因此您可以看到递归中有多少级,是什么导致回溯。如果您发现代码段控制台的输出更具可读性,则可以运行该代码段。
Initially, 1 looks promising because it equals 1, which is still less than 24. We'll try two ways of getting to 24 from here.
First, by adding 5, (1 + 5) looks promising because it equals 6, which is still less than 24. We'll try two ways of getting to 24 from here.
First, by adding 5, ((1 + 5) + 5) looks promising because it equals 11, which is still less than 24. We'll try two ways of getting to 24 from here.
First, by adding 5, (((1 + 5) + 5) + 5) looks promising because it equals 16, which is still less than 24. We'll try two ways of getting to 24 from here.
First, by adding 5, ((((1 + 5) + 5) + 5) + 5) looks promising because it equals 21, which is still less than 24. We'll try two ways of getting to 24 from here.
First, by adding 5, we reached a dead end because (((((1 + 5) + 5) + 5) + 5) + 5) = 26 which is unfortunately already bigger than 24.
Second, by multiplying by 3, we reached a dead end because (((((1 + 5) + 5) + 5) + 5) * 3) = 63 which is unfortunately already bigger than 24.
Sadly we've exhausted all possible ways of getting there from this starting point. We may still be able to get to 24, but not by starting from ((((1 + 5) + 5) + 5) + 5).
Second, by multiplying by 3, we reached a dead end because ((((1 + 5) + 5) + 5) * 3) = 48 which is unfortunately already bigger than 24.
Sadly we've exhausted all possible ways of getting there from this starting point. We may still be able to get to 24, but not by starting from (((1 + 5) + 5) + 5).
Second, by multiplying by 3, we reached a dead end because (((1 + 5) + 5) * 3) = 33 which is unfortunately already bigger than 24.
Sadly we've exhausted all possible ways of getting there from this starting point. We may still be able to get to 24, but not by starting from ((1 + 5) + 5).
Second, by multiplying by 3, ((1 + 5) * 3) looks promising because it equals 18, which is still less than 24. We'll try two ways of getting to 24 from here.
First, by adding 5, (((1 + 5) * 3) + 5) looks promising because it equals 23, which is still less than 24. We'll try two ways of getting to 24 from here.
First, by adding 5, we reached a dead end because ((((1 + 5) * 3) + 5) + 5) = 28 which is unfortunately already bigger than 24.
Second, by multiplying by 3, we reached a dead end because ((((1 + 5) * 3) + 5) * 3) = 69 which is unfortunately already bigger than 24.
Sadly we've exhausted all possible ways of getting there from this starting point. We may still be able to get to 24, but not by starting from (((1 + 5) * 3) + 5).
Second, by multiplying by 3, we reached a dead end because (((1 + 5) * 3) * 3) = 54 which is unfortunately already bigger than 24.
Sadly we've exhausted all possible ways of getting there from this starting point. We may still be able to get to 24, but not by starting from ((1 + 5) * 3).
Sadly we've exhausted all possible ways of getting there from this starting point. We may still be able to get to 24, but not by starting from (1 + 5).
Second, by multiplying by 3, (1 * 3) looks promising because it equals 3, which is still less than 24. We'll try two ways of getting to 24 from here.
First, by adding 5, ((1 * 3) + 5) looks promising because it equals 8, which is still less than 24. We'll try two ways of getting to 24 from here.
First, by adding 5, (((1 * 3) + 5) + 5) looks promising because it equals 13, which is still less than 24. We'll try two ways of getting to 24 from here.
First, by adding 5, ((((1 * 3) + 5) + 5) + 5) looks promising because it equals 18, which is still less than 24. We'll try two ways of getting to 24 from here.
First, by adding 5, (((((1 * 3) + 5) + 5) + 5) + 5) looks promising because it equals 23, which is still less than 24. We'll try two ways of getting to 24 from here.
First, by adding 5, we reached a dead end because ((((((1 * 3) + 5) + 5) + 5) + 5) + 5) = 28 which is unfortunately already bigger than 24.
Second, by multiplying by 3, we reached a dead end because ((((((1 * 3) + 5) + 5) + 5) + 5) * 3) = 69 which is unfortunately already bigger than 24.
Sadly we've exhausted all possible ways of getting there from this starting point. We may still be able to get to 24, but not by starting from (((((1 * 3) + 5) + 5) + 5) + 5).
Second, by multiplying by 3, we reached a dead end because (((((1 * 3) + 5) + 5) + 5) * 3) = 54 which is unfortunately already bigger than 24.
Sadly we've exhausted all possible ways of getting there from this starting point. We may still be able to get to 24, but not by starting from ((((1 * 3) + 5) + 5) + 5).
Second, by multiplying by 3, we reached a dead end because ((((1 * 3) + 5) + 5) * 3) = 39 which is unfortunately already bigger than 24.
Sadly we've exhausted all possible ways of getting there from this starting point. We may still be able to get to 24, but not by starting from (((1 * 3) + 5) + 5).
Second, by multiplying by 3, and guess what...we finally found a solution! Because (((1 * 3) + 5) * 3) = 24. So we can stop now. :)
(((1 * 3) + 5) * 3)
答案 1 :(得分:0)
每当您的current > target
返回null
而您find(current * 3,
($ {history} * 3))
时,都会被评估
假设
((((1 + 5) + 5) + 5) + 5) ---> This is the current value of history
所以当前的当前值为21
现在到达目的地
find(current + 5, `(${history} + 5)`) ||
find(current * 3, `(${history} * 3)`);
它调用 find(21 + 5,(${history} + 5)
),因为current > target
的值,所以此调用返回的值将为null,因为null为falsy值,因此将调用第二个操作数,
find(21 * 3, `(${history} * 3)`); <--- so this is the final value returned form this invocation
因此,这里的历史价值
(((((1 + 5) + 5) + 5) + 5) * 3)
function findSolution(target) {
function find(current, history) {
if (current == target) {
return history;
} else if (current > target) {
console.log(current, ' ---> ', `HISTORY AT NULL: ${history}`);
return null;
} else {
console.log(current,' ---> ', `${history}`);
return find(current + 5, `(${history} + 5)`) ||
find(current * 3, `(${history} * 3)`);
}
}
return find(1, "1");
}
console.log(findSolution(8));