全排列(去重)

之前写过一个全排列没有重复的递归代码,然后花了一点时间研究了一些全排列去重的方法,总结出了这一个算法。之前的有个博客是下一个排列,就是从这个方法分离而出的。
下一个排列
这个方法的思路是这样的,全排列其实也可以看做一个从小到大的排列,其实就是看做从最小一下一下变大,直到最大。
举个例子更容易理解:
12345是第一个数,那么下一个排列就是12354,是所有全排列从小到大排起来,他的下一个数,再下一个就是12435,12453,12534……
那么规律是什么,我们模拟一个变化过程。
12354->12435,我们发现是把百位的3换成了4,那么为什么换成4不换成5,因为需要一步步增大,也就是交换他后面比他大的数里面最小的数,交换3、4后,12354->12453,百位变大后,数就已经变大,所以把百位之后的排成最小数列。然后递归上面的思路,一点点继续换。
这里面有个思路就是,因为我们是找到下一个要换的可以变大的位数,也就是从右往左。还是举例子15432,个位往后没有比他大的,所以找不到可以换上来的,十百千位都是,到万位,后面有比他大的数,也就是说可以有更大的数。整理思路,就是右边有比它大的数的时候,转换成代码思路就是从右往左遍历,第一个比右边数小的。同样我们也就知道,找到的这个位置后面的数列是递增的,因为我们是一步步找过来的,如果不是,到不了现在的位置。然后找后面最小的比此位置大的数字,交换,因为后面是递增的,即使交换后也是,所以我们将后面的字串翻转即可。

class Solution {
public:
    vector<string> Permutation(string str) {
        vector<string> res;
        int len=str.length();
        if(len==0)
            return res;
        else if(len==1)
        {
            res.push_back(str);
            return res;
        }
        vector<char> tmp(len);//vector只有在声明大小的时候,才能直接拿下标赋值,否则只能push_back(这玩意儿困扰了我好久,还是基础不牢固啊,对vector理解不深)
        for(int i=0;i<len;i++)
        {
            tmp[i]=str[i];
        }
        sort(tmp.begin(),tmp.end());//最小的序列
        for(int i=0;i<len;i++)
        {
            str[i]=tmp[i];
        }
        res.push_back(str);
        int left,right;//left记录需要换的位置,right记录后面比left大里最小的位置
        while(1)
        {
            left=-1;
            for(int i=len-1;i>=1;i--)//寻找可换的数
            {
                if(str[i-1]<str[i])
                {
                    left=i-1;//记录位置
                    break;
                }
            }
            if(left==-1)//如果找不到,说明已经是最大,循环结束
            {
                break;
            }
            right=left+1;
            for(int j=left+2;j<len;j++)
            {
                if(str[j]<=str[right]&&str[j]>str[left])//寻找后面比left位置大的最小数
                {
                    right=j;
                }
            }
            swap(str[left],str[right]);//交换
            for(int i=left+1,j=len-1;i<j;i++,j--)//翻转
            {
                swap(str[i],str[j]);
            }
            res.push_back(str);
        }
        return res;
    }
};

看来需要学点做动画的软件了,动画演示思路更直观点。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值