所有字谜 - 递归
Posted
技术标签:
【中文标题】所有字谜 - 递归【英文标题】:all anagrams - recursion 【发布时间】:2015-12-28 13:43:56 【问题描述】:我试图理解下面的递归函数来教自己递归。我试图解释它低于预期的输出和函数本身。我错过了什么?我没有看到你从“abc”到“acb”的过程。我试图理解它让我从“abc”变成了“bac”。
example usage:
var anagrams = allAnagrams('abc');
console.log(anagrams); // [ 'abc', 'acb', 'bac', 'bca', 'cab', 'cba' ]
var allAnagrams = function(string)
var uniqueOutput = ;
(function anagram(ana, str)
// could have also written this as: if(!str)....
if (str === '')
uniqueOutput[ana] = 1;
//recursive call for the length of the anagram.
for (var i = 0; i < str.length; i++)
anagram(ana + str[i], str.slice(0, i) + str.slice(i + 1));
console.log(ana);
)('', string);
console.log(uniqueOutput)
return Object.keys(uniqueOutput);
;
// you are calling the recursive function like this: anagram([anagram=]'', [string=]'abc')
// so the base case is not met on the first iteration since the string isn't empty
// first iteration: i = 0
// anagram('' + 'a' + 'bc' [from str.slice(0 +1)]) ---> resolves to "abc") ---> anagram("abc")
//second iteration: i = 1. we are still in the original call from line 37.
// here below, does "ana" stay as '' since we are still inside the initial recursion call?
//anagram('' + b + a + c) ---- resolves to "bac" ---> anagram("bac")
//third and last iteration iteration: i = 2
//anagram(" " + c + c) ----> anagram("cc") ? not a valid result.
我的新的、正确的(我认为)解释:
//initial input: anagram("", "abc")
//STEP 1: enter the function --> i = 0 for original string "abc"
//anagram("" + "a", "bc") ----> anagram("a", "bc")
//STEP 2: loop through the new, modified string, which is now "bc"
//var i = 0;
//anagram("a" + "b", "c")---> anagram("ab", "c")
//anagram("ab" + "c", [nothing here])
//base case hit, so uniqueOutput["abc"] = 1;
//var i = 1; --> this applies to the string "bc". the loop gets reset to i = 0 once you have a new string to worth with (like below, with "b")
//anagram("a" + "c", "b")
//anagram("ac", "b")
//anagram("ac" + "b", "" )
//base case hit, so uniqueOutput["acb"] = 1;
//STEP 3: increment up on the original string input ("abc") --> so now you are dealing with str[i] === b
//var i = 1;
//anagram("" + "b", "a" + "c")
//anagram("b", "ac") ---> now we need to loop through "ac"!
//anagram("b" + "a", "c")
//anagram("ba", "c")
//anagram("bac", "")---> base case hit, uniqueOutput["bac"] = 1;
//anagram("b", "ac")
//anagram("b" + "c", "a") ---> anagram("bc", "a")
//anagram("bca", "") ---> base case hit, uniqueOutput["bca"] = 1;
//STEP 4: increment up on the original string input ("abc") ---> str[i] === c
//var i = 2;
//anagram ("" + "c", "ab")---> anagram("c", "ab")
//now we need to loop through "ab!" c's index stays the same.
//anagram("c" + "a", "b") ---> anagram("ca", "b")
//anagram("cab", '')---> uniqueOuput["cab"] = 1;
//anagram("c" + "b", "a") ---> anagram("cb", "a")
//anagram("cba", "")----> uniqueOutput["cba"] = 1
【问题讨论】:
您在第一次迭代中错过了第一次调用 anagram 的第二次迭代 【参考方案1】:来自您上面的 cmets:
// first iteration: i = 0
// anagram('' + 'a' + 'bc' [from str.slice(0 +1)]) ---> resolves to "abc") --->
其实在i = 0
上,传递给anagram
的参数是:
anagram('' + 'a', '' + 'bc');
计算结果为:
anagram('a', 'bc');
然后在对anagram
的调用中,我们再次循环遍历str
,它现在只是'bc'。这将导致另外 2 次调用 anagram
,这将是
anagram('a' + 'b', '' + 'c'); // i = 0
anagram('a' + 'c', 'b' + ''); // i = 1
计算结果为:
anagram('ab', 'c');
anagram('ac', 'b');
其中第二个调用将导致对anagram
的另一个调用,并带有以下参数:
anagram('acb', '');
添加到 uniqueOutput
的 str
现在是空的。
只有在执行完所有操作后,代码才会返回到anagram
的最外层调用,i
将根据您的评论递增:
//second iteration: i = 1. we are still in the original call from line 37.
【讨论】:
这真的很清楚。我在反复思考,忘记了对 anagram 的初始调用也将以相同的方式递归评估! 在***调用中,我不会从 0 递增到 1,直到 'abc' 和 'acb' 路径都完成执行,即在我的帖子中提到的所有调用之后。然后我将递增到 1,代码将完全通过“bac”和“bca”路径然后我将递增到 2,代码将完全通过“cab”和“cba”路径(答案已更新) 知道了。所以在 anagram('acb', '');执行,anagram('ab', 'c') ---> anagram('abc', '') 已经执行并存储在 uniqueOutput 中?在这一切完成之后,然后你在外层启动 i++ 的过程,这样 anagram('' + "b", "a" + "c") ---> anagram("b", "ac" ),然后你必须循环遍历“ac”? 是的,就是这样 谢谢!我正在用我更新的(和更好的)解释尝试来更新我的问题。我想我明白了!【参考方案2】:您错过了第二次迭代。这是 cmets 中的执行流程:
// anagram('', 'abc') level 0
// condition false... level 0
// first iteration: i = 0 level 0
// anagram(a', 'bc') ( creating new execution context level 1 )
// condition false.. level 1
// iteration 1... level 1
// anagram('ab', 'c') ( creating new execution context level 2 )
// condition false.. level 2
// iteration 1... level 2
// anagram('abc', '') ( creating new execution context level 3 )
// condition true.. push "abc"
// end for of level 2 context execution
// iteration 2... level 1
// anagram('ac', 'b') ( creating new execution context level 2 )
// condition false.. level 2
// iteration 1... level 2
// anagram('acb', '') ( creating new execution context level 3 )
// condition true.. push "abc" level 3
// end for of level 2 execution
// end for of level 1
// second iteration of level 0....
// keep this pattern till end for of level 0..
// end anagram level 0
如您所见,级别 0 的每次迭代都会向对象推送 2 个单词。如果我们按照你的逻辑,每次迭代都只推一个,考虑到递归就像在那个确切的地方添加更多的代码,一旦函数调用完成,执行流程就会返回到函数调用之前的位置.
【讨论】:
我不明白为什么当您从 anagram('ab', 'c') 转到 anagram ('abc', '') 时我们仍处于迭代第一阶段?我认为这是在第二次迭代中发生的? 因为您处于执行上下文的内部级别,所以在级别 0 中您有 3 次迭代,对吗?以'a'开头..以'b'开头,并以'c'开头,但是一旦您处于级别0的第一次迭代中,就会再次调用anagram,这会创建另一个内部执行上下文,即级别1,对于那个级别,你也有迭代..你需要先进行迭代而不是外部级别的迭代,对于更多的内部级别,与级别 2 相同。以上是关于所有字谜 - 递归的主要内容,如果未能解决你的问题,请参考以下文章