所有字谜 - 递归

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', ''); 

添加到 uniqueOutputstr 现在是空的。

只有在执行完所有操作后,代码才会返回到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 相同。

以上是关于所有字谜 - 递归的主要内容,如果未能解决你的问题,请参考以下文章

字谜递归Scala

我怎样才能得到一个字符串的所有字谜

使用python中的递归解决方案在字符串列表中查找字谜

JavaScript 代码片段

文件中的所有字谜

Python - 递归字谜函数