字符串的排列...逻辑错误?

时间:2014-03-30 03:52:52

标签: java algorithm

我正在尝试生成给定字符串的所有排列。

使用

的逻辑
  

假设string = abcd

     

1)然后我在第一个循环的第一个位置修复'a'(并且类似地每个角色......第一次迭代 - abcd,second-bacd,third-cabd .....)

     

2)然后通过移动第二个字符生成字符串,即'b'   在所有的地方..像abcd,acbd,acdb ...

     

3)然后我将第3个(第4个,第5个等)字符替换为   第二个问题再次重复第二步

     

4)我将abcd改为bacd(对于每个角色都是如此)并重复步骤   2,3 ...

现在不应该生成所有可能的组合..而且我使用树集来删除重复的条目... 但不知何故,它产生的排列数量实际上比4个字符少,只有20个排列......

这是相同的代码..

import java.util.*;

public class practice4 {


    public static void main(String[] args) {



        TreeSet t = new TreeSet();
        String arr[] = new String[100];
        int z = -1;
        StringBuffer s5 = new StringBuffer("abcde");


        for (int i = 0; i <= s5.length() - 1; i++) {

            char ch = s5.charAt(0);
            s5.setCharAt(0, s5.charAt(i));
            s5.setCharAt(i, ch);

            StringBuffer s3 = new StringBuffer(s5);

            for (int j = 1; j <= s3.length() - 1; j++) {

                StringBuffer s2 = new StringBuffer(s3);
                // System.out.println(s2);

                z++;
                arr[z] = s2.toString();

                for (int k = 1; k < s3.length() - 1; k++) {

                    char ch2 = s2.charAt(k);
                    s2.setCharAt(k, s2.charAt(k + 1));
                    s2.setCharAt(k + 1, ch2);
                    // System.out.println(s2);

                    z++;
                    arr[z] = s2.toString();

                }

                if (j >= s3.length() - 1)
                    break;
                char ch3 = s3.charAt(1);

                s3.setCharAt(1, s3.charAt(j + 1));
                s3.setCharAt(j + 1, ch3);

            }

            System.out.println("dooone");

            System.out.println(z);
            for (int x = 0; x <= z; x++) {

                t.add(arr[x]);

            }

        }

        System.out.println(t.size());
        Iterator i55 = t.iterator();
        while (i55.hasNext()) {
            System.out.println(i55.next());
        }
    }

}

2 个答案:

答案 0 :(得分:2)

您的3个嵌套循环可以为长度为n的输入字符串生成最多n ^ 3个字符串。但是,排列的数量要大得多(n!),因此对于大n,结果集必须是部分的。

此外,你的论点是逻辑应该生成所有排列,因为每个字符都在每个可能的位置是不正确的。每个元素访问所有位置的事实并不意味着访问所有可能的安排。例如,对于n = 3:

123
213
321
312

所有项目都出现在所有位置,但列表仍然缺少序列132和231。

如果可以接受递归,请考虑以下解决方案:

public static Collection<String> permutations(String s) {
    ArrayList<String> l = new ArrayList<String>();
    permutations(s.toCharArray(), 0, l);
    return l;
  }

  private static void permutations(char[] chars, int i, ArrayList<String> l) {
    if (i == chars.length) {
      l.add(new String(chars));
      return;
    }

    for (int j = i; j < chars.length; j++) {
      swap(chars, i, j);
      permutations(chars, i + 1, l);
      swap(chars, i, j);
    }
  }

  private static void swap(char[] chars, int i, int j) {
    char tmp = chars[i];
    chars[i] = chars[j];
    chars[j] = tmp;
  }

该算法背后的归纳思想是置换集是长度为n-1的所有排列的并集,这是通过选择第一个字符并继续递归尾部而得到的。假设输入字符串没有重复的字符,这个联合是不相交的,所以我们不必处理重复。

非递归解决方案:

  private static Collection<String> permutations2(String str) {
    ArrayList<String> listNew = new ArrayList<String>();
    ArrayList<String> listPrev = new ArrayList<String>();

    char chr = str.charAt(0);
    listPrev.add("" + chr);

    for (int i = 1; i < str.length(); i++) {
      chr = str.charAt(i);

      for (String s : listPrev) {
        for (int idx = 0; idx <= s.length(); idx++) {
          String perm = s.substring(0, idx) + chr + s.substring(idx);
          listNew.add(perm);
        }
      }

      listPrev = listNew;
      listNew = new ArrayList<String>();
    }
    return listPrev;
  }

我们的想法是,在阶段i中,我们基于前一阶段产生的长度i-1的所有排列,生成长度为i的所有排列。这是通过将新字符插入长度为i-1的每个排列的所有可能位置来完成的。假设原始字符串具有唯一字符,此解决方案还保证结果的唯一性。

答案 1 :(得分:0)