无法生成字符串的所有排列(迭代)

时间:2016-01-27 15:38:58

标签: java string algorithm iteration permutation

所以我正在进行一些Java练习,最近引起我注意的是尝试使用迭代生成String的所有排列。在线有很多例子 - 但是,很多例子看起来非常复杂,我无法遵循。

我尝试使用自己的方法,当使用长度为3的字符串进行测试时,它可以正常工作。方法是(对于每个字母)继续沿着字符串移动一个字母,用它前面的任何字母交换它。例如。

index:  012
string: abc 

(iteration 1) swap 'a' (index 0) with letter after it 'b' (index 0+1) : bac
(iteration 2) swap 'a' (index 1) with letter after it 'c' (index 1+1) : bca
(iteration 3) swap 'a' (index 2) with letter after it 'b' (index 0)   : acb
current permutations: abc (original), bac, bca, acb

(iteration 3) swap 'b' (index 1) with letter after it 'c' (index 1+1) : acb
(iteration 4) swap 'b' (index 2) with letter after it 'a' (index 0)   : bca
(iteration 5) swap 'b' (index 0) with letter after it 'c' (index 1)   : cba
current permutations: abc (original), bac, bca, acb, acb, cba

...

这就是我在Java中实现它的方式:

String str = "abc"; // string to permute
char[] letters = str.toCharArray(); // split string into char array
int setLength = factorial(letters.length); // amount of permutations = n!
HashSet<String> permutations = new HashSet<String>(); // store permutations in Set to avoid duplicates
permutations.add(str); // add original string to set

// algorithm as described above
for (int i = 0; i < setLength; i++) {
    for (int j = 0; j < letters.length; j++) {
        int k;
        if (j == letters.length - 1) {
            k = 0;
        } else {
            k = j + 1;
        }
        letters = swap(letters, j, k);
        String perm = new String(letters);
        permutations.add(perm);
    }
} 

问题是如果我输入一个长度为4的字符串,我最终会得到12个排列(4x3) - 如果我输入一个长度为5的字符串,我最终会得到20个排列(5x4)。

我可以对此算法进行简单的修改以获得所有可能的排列吗?或者这种特殊方法仅适用于长度为3的字符串?

感谢任何反馈!

2 个答案:

答案 0 :(得分:5)

假设输入是&#34; abcd&#34;。这就是你的算法的工作方式

BACD

BACD

BCAD

BCDA

如果你仔细观察,&#34; a&#34;已经定位在所有索引上,以下连续的字母被&#34; a&#34;取代。但是,在您的算法生成&#34; bacd&#34; - 应该跟着&#34; badc&#34;此外,您的输出中将缺少这些内容。

对于长度为4的字符串,当您将排列数计算为阶乘时,您可以理解第一个位置可以占用4个字符,然后是3个,2个和1个。但是,在您的情况下,前两个位置被&#34; ba&#34;第三个位置有两种可能性,即c和d。当您的算法正确找到&#34; cd&#34;时,它无法找到&#34; dc&#34; - 因为,循环不会将问题分解为更多的子问题,即&#34; cd&#34;有两个排列,分别是&#34; cd&#34;和&#34; dc&#34;。

因此,随着字符串长度的增加,您的排列和实际答案的数量差异将会增加。

为了轻松地将问题分解为子问题并解决它,许多算法使用递归。

但是,您可以查看Generate list of all possible permutations of a string以获得良好的迭代答案。

此外,随着字符串长度的增加,不建议计算排列数。

答案 1 :(得分:1)

虽然我不知道如何扩展你当前的切换位置的方法(我之前尝试过这个但没有运气),我知道一种相当直接的方法来实现它

//simple method to set up permutate
private static void permutations(String s)
{
  permutate(s, "");
}

//takes the string of chars to swap around (s) and the base of the string to add to
private static void permutate(String s, String base)
{
  //nothing left to swap, just print out
  if(s.length() <= 1)
    System.out.println(base + s);
  else
    //loop through the string of chars to flip around
    for(int i = 0; i < s.length(); i++)
      //call with a smaller string of chars to flip (not including selected char), add selected char to base
      permutate(s.substring(0, i) + s.substring(i + 1), base + s.charAt(i));
}

这种递归的目标是尽可能多地将处理委托给其他东西,一点一点地解决问题。通过首先选择char,然后告诉函数找出其余部分,可以很容易地解决这个问题。然后可以对每个char进行此操作,直到它们全部被选中一次