31. Next Permutation

来源:互联网 发布:php免费开源微信平台 编辑:程序博客网 时间:2024/05/20 12:46

题目:

Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers.

If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).

The replacement must be in-place, do not allocate extra memory.

Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1

题意:

实现下一个排列,按字母顺序将数列更新到下一个更大的数字排列。

如果那样的序列不存在,那么该序列一定是按照递减的顺序存在的。

只能交换或者替换,不能分配额外的内存空间。

分析:

如果一个排列为A,下一个排列为A_NEXT,那么A_NEXT一定与A有尽可能长的公共前缀。

看具体例子,一个排列为124653,如何找到它的下一个排列,因为下一个排列一定与124653有尽可能长的前缀,所以,脑洞大开一下,从后面往前看这个序列,如果后面的若干个数字有下一个排列,问题就得到了解决。

第一步:找最后面1个数字的下一个全排列。

124653,显然最后1个数字3不具有下一个全排列。

第二步:找最后面2个数字的下一个全排列。

124653,显然最后2个数字53不具有下一个全排列。

第三步:找最后面3个数字的下一个全排列。

124653,显然最后3个数字653不具有下一个全排列。


------插曲:到这里相信大家已经看出来,如果一个序列是递减的,那么它不具有下一个排列


第四步:找最后面4个数字的下一个全排列。

124653,我们发现显然最后4个数字4653具有下一个全排列。因为它不是递减的,例如6453,5643这些排列都在4653的后面。


我们总结上面的操作,并总结出重复上面操作的两种终止情况:

1:从后向前比较相邻的两个元素,直到前一个元素小于后一个元素,停止

2:如果已经没有了前一个元素,则说明这个排列是递减的,所以这个排列是没有下一个排列的。


124653这个排列终止情况是上面介绍的第一种,从后向前比较相邻的2个元素,遇到4<6的情况停止。

并且我们可以知道:

1:124653和它的下一个排列的公共前缀为12(因为4653存在下一个排列,所以前面的数字12保持不变)

2:4后面的元素是递减的(上面介绍的终止条件是前一个元素小于后一个元素,这里是4<6)


现在,我们开始考虑如何找到4653的下个排列,首先明确4后面的几个数字中至少有一个大于4.

4肯定要和653这3个数字中大于4的数字中(6,5)的某一个进行交换。这里就是4要和6,5中的某一个交换,很明显要和5交换,如果找到这样的元素呢,因为我们知道4后面的元素是递减的,所以在653中从后面往前查找,找到第一个大于4的数字,这就是需要和4进行交换的数字。这里我们找到了5,交换之后得到的临时序列为5643.,交换后得到的643也是一个递减序列。


所以得到的4653的下一个临时序列为5643,但是既然前面数字变大了(4653--->5643),后面的自然要变为升序才行,变换5643得到5346.

所以124653的下一个序列为125643.

转载自:http://blog.csdn.net/qq575787460/article/details/41215475 and leetcode题解


算法流程:

1、从右往左,找到第一个违反递增的数(分区数),在例子中,6将会被作为分区数,从右往左8、7、4、3、2是递增的;

2、从右往左,找到第一个大于分区数的数(改变数),在例子中,7是第一个大于6的改变数;

3、交换分区数跟改变数,在例子中,交换数字6和7的位置;

4、将原分区数之后的所有部分逆序存储,即为下一个序列。

代码:12ms

class Solution {public:    void nextPermutation(vector<int>& nums) {        int k = -1; //找到partitionNumber        for (int i = nums.size() - 2; i >= 0; i--) {            if (nums[i] < nums[i + 1]) {                k = i;                break;            }        }         if (k == -1) { //当数组为单调递减序列时,全部倒序,回归到第一个序列            reverse(nums.begin(), nums.end());            return;        }        int l = -1; //找到changeNumber        for (int i = nums.size() - 1; i > k; i--) {            if (nums[i] > nums[k]) {                l = i;                break;            }         }         swap(nums[k], nums[l]); //交换partitionNumber与changeNumber位置        reverse(nums.begin() + k + 1, nums.end());  //将partitionNumber之后的所有元素倒序。    }};
java版:1ms

public class Solution {    public void nextPermutation(int[] nums) {        int n = nums.length;        if(n<2){            return;        }                int index = n-1;        while(index>0){ //找到partitionNumber下标            if(nums[index-1]<nums[index]){                break;            }            index--;        }                if(index==0){  //当该序列为递减序列时,全部倒序,从第一个序列开始            reverseSort(nums, 0, n-1);            return;        }else{             int val = nums[index-1];            int j = n-1;            while(j>=index){ //找到changeNumber所在下标                if(nums[j]>val){                    break;                }                j--;            }            swap(nums, j, index-1);  //交换partitionNumber与changeNumber            reverseSort(nums, index, n-1);  //将partitionNumber之后的所有元素倒序。            return;        }    }        public void swap(int[] nums, int i, int j){        int temp = 0;        temp = nums[i];        nums[i] = nums[j];        nums[j] = temp;    }        public void reverseSort(int[] nums, int start, int end){        if(start>end){            return;        }        for(int i=start; i<=(end+start)/2; i++){            swap(nums, i, start+end-i);        }    }}

0 0