问题:给定字符串S,生成该字符串的全排列。
比如输入为abc,那么输出有以下几种:
即如果输入字符串的长度为N的话,会输出N!个结果。
本文整理了求字符串全排列的若干方法。
方法1 使用STL库的标准函数
C++ STL中提供了std::next_permutation与std::prev_permutation可以获取数字或者是字符的全排列,其中std::next_permutation提供升序、std::prev_permutation提供降序。
1.std::next_permutation函数原型
说明:next_permutation,重新排列范围内的元素[第一,最后一个)返回按照字典序排列的下一个值较大的组合。
返回值:如果有一个更高的排列,它重新排列元素,并返回true;如果这是不可能的(因为它已经在最大可能的排列),它按升序排列重新元素,并返回false。
方法2 仿STL库的标准函数实现
|
|
※ 一个全排列可看做一个字符串,字符串可有前缀、后缀。
生成给定全排列的下一个排列.所谓一个的下一个就是这一个与下一个之间没有其他的。这就要求这一个与下一个有尽可能长的共同前缀,也即变化限制在尽可能短的后缀上。
|
|
【例】 如何得到346987521的下一个
- 从尾部往前找第一个P(i-1) < P(i)的位置
3 4 6 <- 9 <- 8 <- 7 <- 5 <- 2 <- 1
最终找到6是第一个变小的数字,记录下6的位置i-1 - 从i位置往后找到最后一个大于6的数
3 4 6 -> 9 -> 8 -> 7 5 2 1
最终找到7的位置,记录位置为m - 交换位置i-1和m的值
3 4 7 9 8 6 5 2 1 - 倒序i位置后的所有数据
3 4 7 1 2 5 6 8 9
则347125689为346987521的下一个排列
依照上面的讲述不难将代码写出来,如下:
方法3 递归方法求全排列
递归方法很容易理解:分别将每个位置交换到最前面位,之后全排列剩下的位。
递归全排列1
由于递归方法很容易理解,而且网上也有很多的资料,所以不过多讲述,代码如下:
不过需要注意,如果不加入第15行的sort(fromIndex, endIndex);
那么生成的全排列就是非完全升序的.
同时可以对进行修改,使其生成的全排列是完全升序的
递归全排列2
|
|
方法4 递归方法求全排列2
思路是这样的:我们维护两个序列,一个序列是要进行全排列的序列,我们暂称之为源序列,另一个序列是全排列之后的结果序列,我们称其为结果序列。过程如下:
- 初始时源序列为输入的字符串序列,结果序列为空
如果源序列中的元素个数大于1,则对源序列中的每一个元素,进行如下操作:
- 以结果序列+该元素生成新的结果序列
- 将该元素从源序列中剔除并保持其他元素顺序不变生成新的源序列
然后以I产生的结果序列和II产生的源序列为基础递归2)过程
- 如果源序列中元素个数不大于1,则打印结果序列+源序列
下面给出了该思路的C++实现,参考[1][2]
综上,文章介绍了四种字符串全排列的方法:
- 去重: 方法1,方法2
- 不去重按序:方法3-2,方法4
- 不去重不排序:方法3-1
参考: