leetcode 31. Next Permutation(下一个排列)

本文介绍了一个算法,用于在原地将数组重新排列为字典序中下一个更大的排列。如果这样的排列不存在,则将其重新排列为可能的最低顺序(即,按升序排序)。该算法通过查找升序位置并交换适当元素来实现目标,同时确保使用常数额外内存。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 and use only constant 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

给出一个数组,给出下一个排列,也就是找出当前数组的数字排列成的下一个更大的数字
不可以用新的数组,要在原数组中直接交换数字
如果数组是降序,也就是已经是可以排列的最大数字,那么就升序排列,也就是循环的找出最小数字

思路:
从数组的最后一个数字开始向前,找出升序的位置
如[1, 3, 2] , [3,2]的部分是降序的,1到3是升序的,升序的位置在index = 0

找出index=0之后的部分,也就是[3,2]中仅仅大于nums[index]值的,交换
nums[index] = 1, 仅仅大于1的是2,交换1,2,得到[2, 3, 1]

还是index = 0之后的部分,上一步交换之后仍然是降序的,现在按升序排列,得到[2, 1, 3]
即是结果

原理:
降序排列的部分显然已经是最大值了,也就是说index=0之后的部分已经是最大
所以找到下一个排列的方法就是在降序的部分中找到仅仅大于nums[index]的数字,
这样与nums[index]交换以后整体nums就会变大
但是这时不是下一步的排列,把index之后的部分升序才能做到index后的部分是最小数字,实现下一排列的目标

    public void nextPermutation(int[] nums) {
        if(nums == null || nums.length == 0) {
            return;
        }
        
        int n = nums.length;
        int index = n;
        int left = 0;
        int right = n - 1;
        
        //从后往前找到第一个升序的位置
        for(int i = n - 1; i >= 1; i--) {
            if(nums[i - 1] < nums[i]) {
                index = i - 1;
                break;
            }
        }
        
        //调换nums[index]与它后面部分中仅仅大于nums[index]值的
        for(int i = n - 1; i > index; i--) {
            if(nums[i] > nums[index]) {
                //交换元素
                int tmp = nums[index];
                nums[index] = nums[i];
                nums[i] = tmp;
                break;
            }
        }
        
        //index后面的部分现在是降序的,把它升序排列
        //如果整体是降序的,就整体升序排列
        if(index == n) {
            left = 0;
        } else {
            left = index + 1;
        }
        //升序排列
        while(left < right) {
            int tmp = nums[left];
            nums[left] = nums[right];
            nums[right] = tmp;
            left ++;
            right --;
        }
        
    }

也可以先升序排列后面降序的部分,再把降序的前一个元素和后面仅比它大的元素交换。
当整体降序时,可以看到排序后不需要再找交换的元素。

    public void nextPermutation(int[] nums) {
        int n = nums.length;
        if(n == 1) return;
        
        int start = n - 1;
        int left = 0;
        int right = n - 1;
        
        while(start >= 1) {
            if(nums[start - 1] >= nums[start]) start --;
            else break;
        }
            
        //Arrays.sort(nums, start, n);
        left = start;
        right = n - 1;
        while(left < right) {
            int tmp = nums[right];
            nums[right] = nums[left];
            nums[left] = tmp;
            left ++;
            right --;
        }
        
        if(start == 0) return;
        
        for(int i = start; i < n; i++) {
            if(nums[i] > nums[start - 1]) {
                int tmp = nums[i];
                nums[i] = nums[start - 1];
                nums[start - 1] = tmp;
                break;
            }
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝羽飞鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值