其他分享
首页 > 其他分享> > 31. 下一个排列

31. 下一个排列

作者:互联网

难度 medium
实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。

如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。

必须 原地 修改,只允许使用额外常数空间。

示例 1:

输入:nums = [1,2,3]
输出:[1,3,2]
示例 2:

输入:nums = [3,2,1]
输出:[1,2,3]
示例 3:

输入:nums = [1,1,5]
输出:[1,5,1]
示例 4:

输入:nums = [1]
输出:[1]

提示:

1 <= nums.length <= 100
0 <= nums[i] <= 100

解题思路:这道题的解题思路是这样的:
我们需要在nums找一个大数替换前面的小数,从而使其变大,而这个数还必须尽量小,这个特点就意味着我们需要从后向前遍历。
一开始的思路是,从后往前遍历,每个数cur都与前面的数进行比较,比较的时候也是从后往前遍历,如果遍历到的数比当前的数小,那就交换他俩的位置,大数换到前面后,从大数开始,后面的数进行升序排列,因为升序排列就是最小序,因此问题的关键在于找到交换的大数和小数。假如我们简单地按上面的思路来,如nums=[1,2,3],很明显遍历过程是3和2比较,3>2,因此3和2互换,这样就是res=[1,3,2],但是对于nums=[4,2,0,2,3,2,0]这种情况,可以看到,按上面的方法的话,结果应该是第6位的2和第3位的0进行互换,结果是[4,2,2,0,0,2,3],这结果就不对了,正确结果是[4,2,0,3,0,2,2],因为我们这种做法,第3位的0和第6位的2组成的可互换的数对[0,2]的优先级,比第4位的2和第5位的3组成的数对[2,3]更高,这两组数对都符合我们方法的定义,但是其实[2,3]的优先级应该比[0,2]更高才对。我们重新考虑一下,寻找下一个最小序,如果从最后一个数往前数,一直是升序的,也就是大数都排在小数前面,那无论如何我们都是找不到可以交换的两个数的,因此我们的首要目标,应该是找到第一个从后往前是降序的数对,这样我们才能保证小数在前面,大数在后面,这样才有交换的可能,也就是i从后往前遍历,需要满足nums[i]>nums[i-1],这样i-1这个位置就是我们要找的小数,然后我们从这个位置到nums的结尾进行遍历,找到大于nums[i-1]而且又是满足条件的所有数最小的数,因为从上一步可以知道,从i到数组结尾这段是降序的,因此我们找到第一个小于nums[i-1]的数,设其索引为j,则j-1就是最后一个大于nums[i-1]的数,我们先把nums[j-1]和nums[i-1]交换一下,其实是先给nums[i-1]赋值,从i-1之后,就是按照最小序进行排序,这样就是下一个最邻近的排列了。

标准的“下一个排列”算法可以描述为:

  1. 从后向前查找第一个相邻升序的元素对 (i-1,i),满足 A[i-1] < A[i]。此时 [i,end) 必然是降序
  2. 在 [i,end) 从后向前查找第一个满足nums[j]<=nums[i-1]的j,此时j-1就是最后一个满足 A[i-1] < A[j] 的索引,也就是大数的位置。A[i-1]、A[j-1] 分别就是上文所说的「小数」、「大数」
  3. 将 A[i-1] 与 A[j-1] 交换
  4. 可以断定这时 [i, end) 必然是降序,逆置 [i,end),使其升序
  5. 如果在步骤 1 找不到符合的相邻元素对,说明当前 [begin,end) 为一个降序顺序,则直接跳到步骤 4

代码t100 s54 java

class Solution {
    public void nextPermutation(int[] nums) {
        int len = nums.length;
        for(int i=len-1; i>0; i--){
            if(nums[i-1]<nums[i]){
                int j=i;
                for(; j<len; j++){
                    if(nums[j]<=nums[i-1]) break;
                }
                swap(nums, i-1, j-1);
                int left = i, right = len-1;
                while(left<right){
                    swap(nums, left++, right--);
                }
                return;                
            }
        }
        for(int i=0; i<len/2; i++){
            swap(nums, i, len-1-i);
        }
        return;
    }

    public void swap(int[] nums, int i, int j){
        int t = nums[i];
        nums[i] = nums[j];
        nums[j] = t;
    }
}

代码 t100 s40 cpp

class Solution {
public:
    void nextPermutation(vector<int>& nums) {
        int n = nums.size(), i, j;
        for(i=n-2; i>=0; i--){
            if(nums[i+1]>nums[i]){
                for(j=n-1; j>i; j--){
                    if(nums[j]>nums[i]) break;
                }
                swap(nums[i], nums[j]);
                reverse(nums.begin()+i+1, nums.end());
                return;
            }
        }
        reverse(nums.begin(), nums.end());
    }
};

参考资料
https://leetcode-cn.com/problems/next-permutation/solution/xia-yi-ge-pai-lie-suan-fa-xiang-jie-si-lu-tui-dao-/
https://www.cnblogs.com/grandyang/p/4428207.html

标签:排列,end,从后,nums,一个,31,遍历,升序
来源: https://www.cnblogs.com/zhengxch/p/14726505.html