所以我正在进行一些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的字符串?
感谢任何反馈!
答案 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进行此操作,直到它们全部被选中一次