您的位置:首页 > 其它

算法-字符串的全排列

2016-10-14 18:36 190 查看
来源:编程之法:面试和算法心得 July

题目描述:输入一个字符串,打印出该字符串中字符的所有排列。例如,输入字符串“abc”,则输出“abc”、“acb”、“bac”、“bca”、“cab”和“cba”。

分析与解法:

解法一:递归实现 (递归理解起来也挺费劲,就像当初理解汉诺塔类似)

从字符串中选出一个字符作为排列的第一个字符,然后对剩余的字符进行全排列。如此递归处理,从而得到所有字符的全排列。

参考代码:

void CalcAllPermutation (char * perm, int from, int to)
{
if (to <= 1)
{
return;
}
if (from == to)
{
for (int i = 0; i <= to; i++)
{
count << perm[i];
}
cout << endl;
}
else
{
for (int j = from; j <= to; j++)
{
swap(perm[j], perm[from]);
CalcAllPermutation(perm, form+1, to);
swap(perm[j], perm[from]);
}
}
}

解法二:字典序排列
维基百科定义:给定两个偏序集A和B,(a, b)和(a’,b’)属于笛卡尔积 A * B,则字典序定义为(a, b)<=(a’,b’)当且仅当a <a' 或a = a'且b <= b'。

根据上述字典序定义可知,如果给定两个字符串,从起点开始将它们对应的字符逐个进行比较,则先出现较小字符的那个字符串的字典序小;如果字符一直相等,则较短的那个字符串的字典序小。那么,有没有执行的起点、终点、过程如下的算法呢?

算法起点:字典序最小的排列1-n,如“12345”。

算法终点:字符序最大的排列n-1,如“54321”。

算法的执行过程:从当前排列生成字典序刚好比它大的下一个排列。

答案是肯定的,这就是C++标准库中的next_permutation函数实现 的算法。

假定现有字符串AxB,它的下一个排列是AyB',其中A、B和B'是字符串(可能为空),x和y是字符,前缀相同,都是A,且一定有y > x。那么,为了使下一个排列字典顺序尽可能小,必有:A尽可能长,而y尽可能小,最后B'里的字符按由小到大递增排列。现在的问题是,如何确定x和y呢?

来看一个例子。例如,要找21543的下一个排列,则可以从左到右逐个扫描每个数,看哪个能增大(即如果一个数的右面有比它大的数存在,那么这个数就能增大),可以看到最后一个能增大的数是:x = 1。而1应该增大到多少呢?1能增大到它右面比它大的那一系列数中最小的那个数,即y=3,故此时21543的下一个排列应该变为23xxx,显然xxx应由小到大排列,于是最终找到比21543大但字典顺序尽量小的23145.

先来定义升序,即相邻两个位置ai < a i+1, ai称作该升序的首位。

由上述例子可以得出next_permutation算法的具体步骤(二找、一交换、一翻转)如下。

1、找到排列中最后(最右)一个升序的首位位置i, x= ai

2、找到排列中第i位右边最后一个比ai大的位置j,y = aj

3、交换x和y

4、把第i+1位到最后的部分翻转(执行此步骤前,因为第i位是最后一个升序的位置,所以从i+1到n一定是降序排列的,而执行此步骤后,从i+1到n变成升序排列)

参考代码:

void CalcAllPermutation (char * perm, int num)
{
int i;
// 1、找到排列中最后一个升序的首位位置i,x = ai
for (i = num -2; (i >= 0) && (perm[i] >= perm(i+1)); --i)
{
;
}
// 已经找到所有排列
if (i < 0)
{
return false;
}
int k;
// 2、找到排列中第i位右边最后一个比ai大的位置j,y = aj
for (k = num - 1; (k > i) && (perm[k] <= perm[i]); --k)
{
;
}
// 3、交换x和y
swap(perm[i], perm[k]);
// 4、把第i+1位到最后的部分翻转
reverse(perm + i + 1, perm + num);

return true;
}

然后在主函数里循环判断和调用CalcAllPermutation函数即可按照字典顺序输出所有排列。由于全排列共有n!种排列情况,所以不论是递归法还是字典序排列,时间复杂度都为O(n!)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: