给一个字符串(包含重复字符),打印它的所有可能的组合。

这是一个很老的题目,从我大学毕业开始找工作就碰到它了,但真正能正确编出它的人却很少。而网上搜来的代码,不是错误,就是思维不够清晰。就我自己而言,一时写对,时间一长再写它,就错误多多,现在我就来总结一下,和大家分享一下编成的快乐!

首先我们来说一下这个问题的基本算法,其实很简单,是一个典型的递归算法:

假设给定的字符串是 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步中求解了)

                    }

                }

            }

        }

    }

 

点赞