LeetCode-下一个排列

(一)题目描述

实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列(即,组合出下一个更大的整数)。如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。必须 原地 修改,只允许使用额外常数空间。

示例:

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

 

(二)解题思路

1、思路重点:如何保证下一排列是大于当前排列的最小排列?

(1)动的元素越靠后越好,所以需从后向前查找

(2)前面被动的元素增幅越小越好

2、思路如下:

(1)从后向前查找第一个相邻的升序对,下标分别为i(前)、j(后)(此时i、j后面的元素均为降序,降序中的任何一个元素被后面的元素换,该排列都不会变大,所此时较小的元素为最适合被动的元素,因其靠很靠后)

(2)在[j,end]区间从后向前查找刚好大于nums[i]的第一个元素,然后与nums[i]交换;

(3)将[j,end]的元素进行升序排列(保证该排列增幅最小)

(4)若[0,end]的元素全为降序,则全部升序排列

3、借鉴力扣大佬的流程可视化,方便理解:以下解析网址为:力扣

以求 12385764 的下一个排列为例:

首先从后向前查找第一个相邻升序的元素对 (i,j)。这里 i=4j=5,对应的值为 57

然后在 [j,end) 从后向前查找第一个大于 A[i] 的值 A[k]。这里 A[i] 是 5,故 A[k] 是 6

将 A[i] 与 A[k] 交换。这里交换 56

这时 [j,end) 必然是降序,逆置 [j,end),使其升序。这里逆置 [7,5,4]

因此,12385764 的下一个排列就是 12386457

最后再可视化地对比一下这两个相邻的排列(橙色是蓝色的下一个排列):

(四)代码如下:

class Solution15 {
    public void nextPermutation(int[] nums) {
//        (1)从右到左记录降序;
//  原则:(1)交换的两数尽量靠右,增加的大小尽量小,才能使增加的幅度尽量小
//        步骤:(1)从右到左找第一个降序对
//             (2)该降序对后面的所有数必为从右到左的升序
        int smallIdx=0, largeIdx=0;
        int temp=0;
        int flag=0;
        for (int i = nums.length - 1; i >= 0; i--) {
            if (i > 0 && nums[i] > nums[i - 1]) {
                flag=1;
                smallIdx=i-1;
                break;
            }
        }
        if(flag==0){
            Arrays.sort(nums);
            return;
        }
        for (int i = nums.length-1; i >=smallIdx+1 ; i--) {
            if(nums[i]>nums[smallIdx]){
                temp=nums[i];
                nums[i]=nums[smallIdx];
                nums[smallIdx]=temp;
                break;
            }
        }
        Arrays.sort(nums,smallIdx+1,nums.length);
    }
}

二刷错误解答:

class Solution {
    public void nextPermutation(int[] nums) {
//        (1)从右到左记录降序;
        int temp = 0;
        int flag = 0;
        for (int i = nums.length - 1; i >= 0; i--) {
            if (i>0&&nums[i] > nums[i - 1]) {
                temp = nums[i];
                nums[i] = nums[i - 1];
                nums[i - 1] = temp;
                flag=1;
                break;
            }
        }
        if(flag==0){
            Arrays.sort(nums);
        }
    }
}

!!错误原因:只考虑到从后往前查找第一个处于降序的序列,但找到后的处理方法只是简单的将该降序对的两个值进行交换(即(i,j)位置的值),没考虑到[j,end]这个区间存在比i处的值小的值,
将[j,end]这个区间小且最接近num[i]的值与Num[i]交换,这样得到的值总体才会最小。 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值