如何找到一个字符串的所有排列?

链接: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);
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值