这是一个很老的题目,从我大学毕业开始找工作就碰到它了,但真正能正确编出它的人却很少。而网上搜来的代码,不是错误,就是思维不够清晰。就我自己而言,一时写对,时间一长再写它,就错误多多,现在我就来总结一下,和大家分享一下编成的快乐!
首先我们来说一下这个问题的基本算法,其实很简单,是一个典型的递归算法:
假设给定的字符串是 babc ([]中的为下一次递归的输入):
1. abbc 排序: 让相等的字符连续
2. a[bbc] 求解以第一个字符开头的组合
|
3. b[abc] 发现第二个字符b和上一组组合的头a 不相等,所以调换,并求解一新头(b) 开头的组合
4. abbc 还原上一次的交换
|
5. abbc b和第3步中的第一个字符b相等跳过(以b开头的组合已经在第3步中求解了)
|
6. c[bba] c和上一组组合的头(b) 不相等,所以调换,并求解一新头(c)开头的组合
以下是我整理的源码(注释和上面的算法对应):
class Program
{
static void Main(string[] args)
{
permutation(“babc”);
}
static void permutation(string input)
{
char[] temp = input.ToCharArray();
//abbc 排序: 让相等的字符连续
Array.Sort(temp);
SubPermutation(temp, 0);
Console.WriteLine(count);
}
//用来记录共有多少种组合
static int count = 0;
//start是剩余字符串的第一个字符的位置
static void SubPermutation(char[] input, int start)
{
if (start == input.Length-1)
{
//递归出口,即需要求的字符为最后一个字符
foreach (char c in input)
{
Console.Write(c + ” “);
}
Console.WriteLine();
count++;
}
else
{
char head = input[start];
for (int i = start; i < input.Length; ++i)
{
if (i == start)
{
//求解以第一个字符开头的组合
SubPermutation(input, start + 1);
}
else
{
if (input[i] != head)
{
//b[abc] 发现第二个字符b和上一组组合的头a 不相等,所以调换.
//exchange
char temp = input[start];
input[start] = input[i];
input[i] = temp;
//update head to current head.
head = input[start];
//并求解一新头(b) 开头的组合
//deal with left item.
SubPermutation(input, start + 1);
//还原上一次的交换
//exchange
temp = input[start];
input[start] = input[i];
input[i] = temp;
}
// b和第3步中的第一个字符b相等跳过(以b开头的组合已经在第3步中求解了)
}
}
}
}
}