理解此算法以查找字符串的排列(递归)

时间:2016-09-24 15:19:24

标签: java algorithm

我正在阅读我的教科书,而我无法真正理解这是如何以递归的方式生成字符串的排列

class PermutationIterator
{
    private String wrd;
    private int current;
    private PermutationIterator Iter;
    private String tl;
    // Constructor
    public PermutationIterator(String s)
    {
        wrd = s;
        current = 0;
        if (wrd.length() > 0)
            Iter = new PermutationIterator(wrd.substring(1));
    }

    public String nextPermutation()
    {
        if(wrd.length() == 0)
        {
            current++;
            return "";
        }

        char c = wrd.charAt(current);
        String nextPermut = Iter.nextPermutation();
        if(!Iter.hasMorePermutations())
        {
            System.out.println("Current value is " + current + " word length is " + wrd.length());
            current++;
            if (current >= wrd.length()) {
                Iter = null;
            }
            else
            {
                if (current + 1 >= wrd.length())
                    tl = wrd.substring(0,current);
                else
                    //System.out.println("Reached");
                    tl = wrd.substring(0,current) + wrd.substring(current + 1, wrd.length());
                    Iter = new PermutationIterator(tl);
            }
        }
        return c + nextPermut;
    }

    public boolean hasMorePermutations()
    {
        System.out.println("Inside this method we have current= " + current + " with wrdlength "  + wrd.length() +"with the word " + wrd);
        return current < wrd.length();
    }
}

调用
public static void main(String [] args)
    {
        PermutationIterator iter = new PermutationIterator("eat");
        while(iter.hasMorePermutations())
        {
            System.out.println(iter.nextPermutation());
        }
    }

对于eat,这将输出 eat eta aet ate tea tae

我的尝试

在尝试理解所有内容之前,过去三天我一直在努力弄清楚到达!Iter.hasMorePermutations()的确切程度。这可能是假的唯一方法是return current < wrd.length();不成立。即wrd.length() <= current

现在这里真的开始失去我。我尝试在!Iter.hasMorePermutations()分支内打印出word.length和current的值,只是为了看看发生了什么。

Current value is 0 word length is 1 Current value is 0 word length is 2 eat

等等..这怎么可能?不是我们达到这个分支的条件,当前值大于我们的字长吗?我们是如何到达这个分支的?

我还附上了我试图追踪该计划的图片,enter image description here

感谢您阅读本文!

5 个答案:

答案 0 :(得分:1)

对于每个字长,一次有4个迭代器处于活动状态。它们都有自己的current值,对hasMorePermutations的调用是检查下一个迭代器上currentlength的值,而不是自身。所以你可能想输出:

System.out.println("Current value is " + Iter.current + " word length is " + Iter.wrd.length());

首先,他们所有的当前值都是0,所以我们必须“吃”:

(word = 'eat', current = 0, length = 3)
 (word = 'at', current = 0, length = 2)
  (word = 't', current = 0, length = 1)
   (word = '', current = 0, length = 0)

每个迭代器在下一个迭代器上调用nextPermutation,直到我们到达最后一个迭代器,其current值递增,因为wrd.length() == 0。所以我们得到:

(word = 'eat', current = 0, length = 3)
 (word = 'at', current = 0, length = 2)
  (word = 't', current = 0, length = 1)
   (word = '', current = 1, length = 0)

这是在第三个迭代器Iter.hasMorePermutations()中检测到的,然后它将递增自己的current值并重置最后一个迭代器:

(word = 'eat', current = 0, length = 3)
 (word = 'at', current = 0, length = 2)
  (word = 't', current = 1, length = 1)
   (word = '', current = 0, length = 0)

第二个迭代器也会类似地检测到它,它会重置最后两个迭代器:

(word = 'eat', current = 0, length = 3)
 (word = 'at', current = 1, length = 2)
  (word = 'a', current = 0, length = 1)
   (word = '', current = 0, length = 0)

第一个迭代器对Iter.hasMorePermutations()的调用将返回false,因此它不会递增其当前值,从而提供下一个字符串&#39;。

答案 1 :(得分:0)

您要打印的内容是wrd对象的currentthis的值,而不是评估Iter的对象!Iter.hasMorePermutations()的值。< / p>

要了解发生了什么,您应该打印Iter.wrd.length()Iter.current

答案 2 :(得分:0)

我猜你所缺少的是测试不是this.hasMorePermutations(),而是Iter.hasMorePermutations(),可能会被Iter看起来像一个类名而不是一个字段名称......

所以,在你的第3点返回之前,它有字长0和当前1,也就是说,不再有迭代,当它返回到父节点时它就是被测试的对象,所以你输入if语句。

答案 3 :(得分:0)

在图3中的

它属于这个if分支

        if(wrd.length() == 0)
        {
            current++;
            return "";
        }

执行此分支后,现在wrd.length()为0且current为1, 因此,在nextPermutation点击此if分支后,下一次立即调用hasMorePermutations将返回false

答案 4 :(得分:-1)

什么这么复杂?我阅读代码并翻译成英文的方式是:

for(current=0 to string_len)

  1. current

  2. 的位置选择该字母
  3. 从字符串中提取出来(创建一个缺少该字母的字符串)。 (这将减少一个长度;我在这里陈述明显的吗?)

  4. 递归地生成在prev步骤中构造的字符串的排列(称之为tl),注意将提取的字母添加为每个字母的第一个字母。在缩短的tl字符串

  5. 上生成的排列

    current到达string_len时,没有更多的字母要提取,这意味着你已经完成了。

    这是一个海龟一直向下的情况&#34; - 一个3个字母的迭代器将使用一个2个字母的迭代器,它将使用一个单字符迭代器,它将使用一个空字符串迭代器。

    在每个级别,迭代器将提取current个字母,创建一个level-1迭代器,然后将其压缩干净&#39;当它没有任何东西可以提供时丢弃它。一旦current达到最大值,此迭代器将向level+1报告&#34;我干涸&#34;并被解雇。

    -

    "Rubber duck debugging"了解如何达到!Iter.hasMorePermutations()

    空字符串

    • set current = 0
    • 提取第一个字母 - 我不能current == len,因此:
      1. 首次调用时返回空字符串(并增加当前值)
      2. 通话时,告诉来电者&#39; false == hasMorePermutation()&#39;

        if(wrd.length() == 0)
        {
            current++;
            return "";
        }
    

    带有1个字母的字 - 使其成为&#34; t&#34;

    • set current = 0
    • 在当前提取信件 - first_letter =&#39; t&#39 ;; tl =&#34;&#34;
    • 使用空字符串置换迭代器生成tl(空字符串)的第一个排列(参见上文)

      String nextPermut = Iter.nextPermutation();

    只有一种可能,因为它是一个空字符串。当我,单字母迭代器,得到我的子迭代器(空字符串一)&#34;你有更多的排列&#34;答案将出现否定

        if(!Iter.hasMorePermutations()) 
            // this is true immediately for my empty-str subiterator
    

    那么,我,单字母迭代器会做什么?

    将增加我的current然后......

    因为下次我会被问到,我不能再生成一个,我将解雇我的(零长度)迭代器

            if (current >= wrd.length()) {
                Iter = null;
            }
    

    然后将提取的字母(我唯一的一个)返回到我的(已经被解雇的)迭代器生成的排列之前:从而返回一个&#34; t&#34;前面是一个空字符串。

    我,单字母迭代器下次我会问hasMorePermutations时会回答什么?好吧,false,因为我将current增加到字符串的长度(1)

    你真的希望我继续吗,或者你是否已经看到使用迭代器的迭代器用于一个不用字母的单词,每个迭代器都有自己的current和单词&#39; ?