Next Permutation之字典序法

来源:互联网 发布:深圳国税开票软件下载 编辑:程序博客网 时间:2024/06/06 04:25

字典序法是求出当前数组在字典序下的下一个数组,也就是正好比当前数组稍大的下一数组。笔者是从《组合数学》中看到的算法,但当时并没有深入思考,而当在leetcode上看到了next permutation才知道该算法的经典。

算法的思路如下:

(1)求满足下列不等式的最大的j,记为i, 即

i=max{j | nj-1<nj}

(2)求满足下列不等式的最大的k,记为h,即

h=max{k | ni-1<nk}

(3)将ni-1和nh交换,这时数组从i位开始都是递减的,所以将数组从第i位开始到最后这一部分进行180度旋转,得到最终的数组了。

下面分析一下算法,为什么通过这个算法得到的就是比原来数组大的最小的数组呢?首先,nh是比ni-1大的最小整数,为什么呢,nh不是只是比ni-1大的最靠后的数字而已吗,其实从nh开始,他后面的不可能有比ni-1大的数,然后在i到h这一段,nh又恰好是最小的那个数,因为如果这一段出现了比nh小的数,那么第(1)个条件就不满足了。所以将ni-1和nh交换是肯定对的。然后,交换完以后,从第i位到第h位都是比原来的ni-1大的数,因为他们比nh都要大,然后根据第(2)个条件,从第h+1位开始到最后都是比原来ni-1小的数,所以从第i位开始到最后形成了一个递减的序列,因此此时再将这一序列颠倒一下便可得到题目所求的数组了。

算法的代码如下:

void nextPermutation(vector<int>& nums) {if(nums.size()<2)return;//find a max index i, from i to the end is descendingint ase_max=-1;for(int i=1;i<nums.size();i++){if(nums[i]>nums[i-1]){ase_max=i;}}if(ase_max==-1){//the nums is descendingfor(int i=0;i<nums.size()/2;i++){swap(nums[i],nums[nums.size()-i-1]);}return;}//find a max index k, where nums[k] is the smallest num that is bigger than nums[i-1]int bigger_max=ase_max;for(int i=ase_max-1;i<nums.size();i++){if(nums[i]>nums[ase_max-1])bigger_max=i;}//swap the nums[i-1] and nums[k]swap(nums[ase_max-1],nums[bigger_max]);//reverse the numbers from nums[i] to nums[size-1], because these numbers are deasendingfor(int i=0;i<(nums.size()-ase_max)/2;i++){swap(nums[ase_max+i],nums[nums.size()-i-1]);}}
希望能对大家有所帮助

0 1