【问题标题】:permutations of a string...logic error?字符串的排列...逻辑错误?
【发布时间】:2014-03-30 03:52:52
【问题描述】:

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

我使用的逻辑

假设字符串 =abcd

1) 然后我在第一个循环的第一个位置修复'a'(以及类似的每个字符.. 第一次迭代 - abcd、第二个-bacd、第三个-cabd .....)..

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

3) 然后我用 第二个字符并再次重复第二步

4)我将 abcd 更改为 bacd(每个字符都为 n)并重复步骤 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());
        }
    }

}

【问题讨论】:

  • 我没有完全听从你的解释,但只要看看你的代码有 3 个嵌套循环这一事实,我就知道它不适用于大于 3 的字符串长度。更好的方法要生成没有重复的排列,就是尝试将每个字符放在位置 1,并且对于每种可能性,递归调用例程以查找剩余字符的所有排列的列表。然后,您只需将每个这样的子排列附加到您当前的第一个字符。
  • 这篇文章需要的算法有很好的解释:stackoverflow.com/questions/756055/…
  • @j_random_hacker.. 是的,它不适用于 3 个或更多字符。事实上,它仅适用于 3 个字符。但是这个逻辑应该生成所有组合,因为每个字符都在每个可能的位置。 ..那么我无法理解为什么它不会..如果你可以的话,请帮忙,否则我将不得不尝试递归地做......

标签: java algorithm


【解决方案1】:

对于长度为 n 的输入字符串,您的 3 个嵌套循环最多可以生成 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 的每个排列的所有可能位置中插入新字符来完成的。该解决方案还保证了结果的唯一性,假设原始字符串具有唯一字符。

【讨论】:

  • 但我不会查看解决方案,而是尝试提出另一种可行的算法:)
【解决方案2】:

【讨论】:

  • 谢谢,但不,谢谢..如果你能帮助解决错误的逻辑,请回答
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-18
相关资源
最近更新 更多