链接:https://www.nowcoder.com/questionTerminal/ab975d2d843b4f8593074930e03beaf7?source=relative
来源:牛客网
递归实现
算法思想:求n位的字符串的全排列,先确定第0位,然后对后面n-1位进行全排列,在对n-1为进行全排列时,先确定第1位,然后对后面的n-2位进行全排列...由此得到递归函数和递归的结束条件。全排列也就是交换位置,到n-2位时,就是将n-2和n-1交换位置。
从集合中依次选出每一个元素,作为排列的第一个元素,然后对剩余的元素进行全排列,如此递归处理,从而得到所有元素的全排列。以对字符串abc进行全排列为例,我们可以这么做:以abc为例
- 固定a,求后面bc的排列:abc,acb,求好后,a和b交换,得到bac
- 固定b,求后面ac的排列:bac,bca,求好后,c放到第一位置,得到cba
- 固定c,求后面ba的排列:cba,cab。
void CalcAllPermutation(char* perm, int from, int to)
{
if (to <= 1)
{
return; //递归出口
}
if (from == to) //输出条件 to表示字符串最后一位下标
{
for (int i = 0; i <= to; i++)
cout << perm[i];
cout << endl;
}
else
{
for (int j = from; j <= to; j++)
{
swap(perm[j], perm[from]); //关键
//交换位置后,输出以perm[j]不变,后面的字母改变的所有排列
CalcAllPermutation(perm, from + 1, to);
swap(perm[j], perm[from]);
}
}
}
但是以上算法会出现一个问题,比如字符串为abb,结果会出错:
链接: https://www.jianshu.com/p/f051a4ae6e93
来源:简书
字符串全排列递归算法的改进
出现以上问题的原因,主要是因为相同的字符进行了多次交换。举个栗子abb,a固定时,后面的字符位置不变,得到abb,当第2个b和第3个b交换时,又得到了abb,解决这个问题的思路在于,在交换时进行判断,如果后面的字符有重复就不交换。当第i个字符和第j个字符交换位置时,判断范围是[i,j)是否有和j重复的数,代码如下:
bool isSwap(char *list, int begin, int end) {
for (int i = begin; i < end; i++){
if (list[i] == list[end])
return false;
}
return true;
}
#define SWAP(x,y,t) ((t) = (x),(x) = (y),(y) = (t))
void perm(char *list, int i, int n){
int j, temp;
if (i == n) {
printf("\t%s\n", list);
}
else {
for (j = i; j <= n; j++){
if (isSwap(list, i, j)) {
//使用宏定义,传的是数值,如果这的swap用函数实现,传的应该是指针
SWAP(list[i], list[j], temp);
//交互位置后,输出以list[j]不变,后面的字母改变的所有排列
perm(list, i + 1, n);
SWAP(list[i], list[j], temp);
}
}
}
int main(){
char list[] = "abc";
perm(list, 0, strlen(list)-1);
}