[LeetCode]31. Next Permutation

31. Next Permutation

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,31,3,2
3,2,11,2,3
1,1,51,5,1

分析

题目没有说得很清晰什么叫做一个排列的下一个更大的字典序排列,其实下一个更大的字典序排列需要经过四个步骤:

下一个更大的字典序排列

步骤1:从当前排列的右端往左端遍历,找到第一个违反升序的元素pivot,图中为元素6
步骤2:再从当前排列的右端往左端遍历,找到第一个比pivot大的元素changeNumber,图中元素为7
步骤3:将pivot和changeNumber交换
步骤4: 将pivot右端的序列翻转

如果pivot不存在则直接翻转原排列即可。
清楚了上面的步骤直接编码。

源码

class Solution {
public:
    void nextPermutation(vector<int>& nums) {
        if(nums.size() < 2) return;

        int i = nums.size() - 1;
        int j = -1; // 1. 反向寻找到的pivot位置
        while(i > 0) {
            if(nums[i] > nums[i - 1]) { // 后一个数 < 前一个数
                j = i - 1;
                break;
            }
            i--;
        }

        if(j == -1) { // 说明序列是降序,只要翻转序列即可
            reverse(nums, 0, nums.size());
        } else { // 2. 序列存在下一个更大的排列,在nums.size() - 1,...,j+1间找到第一个比nums[j]要大的数
            int k = nums.size() - 1;
            while(k > j) {
                if(nums[k] > nums[j]) break;
                k--;
            }
            //3. 找到了交换的位置为k
            swap(nums[j], nums[k]);
            //4. 翻转交换后的序列
            reverse(nums,j + 1, nums.size() - j - 1);
        }
    }

    // 翻转一个序列
    void reverse(vector<int>& nums, int start, int length) {
        int middle = length / 2;
        int i = 0;
        while(i < middle) {
            swap(nums[start + i], nums[start + (length - 1 - i)]);
            i++;
        }
    }

    // 不占用额外空间交换两个数
    void swap(int& a, int& b) {
        a = a + b;
        b = a - b;
        a = a - b;
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值