力扣31题-下一个排列


力扣31题-下一个排列

整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。
例如,arr = [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。
整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。
更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,那么数组的 下一个排列 就是在这个有序容器中排在它后面的那个排列。
如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。
例如,arr = [1,2,3] 的下一个排列是 [1,3,2] 。
类似地,arr = [2,3,1] 的下一个排列是 [3,1,2] 。
而 arr = [3,2,1] 的下一个排列是 [1,2,3] ,因为 [3,2,1] 不存在一个字典序更大的排列。
给你一个整数数组 nums ,找出 nums 的下一个排列。
必须 原地 修改,只允许使用额外常数空间。

一、问题描述

整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。
例如,arr = [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。
整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。
更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,那么数组的 下一个排列 就是在这个有序容器中排在它后面的那个排列。
如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。
例如,arr = [1,2,3] 的下一个排列是 [1,3,2] 。
类似地,arr = [2,3,1] 的下一个排列是 [3,1,2] 。
而 arr = [3,2,1] 的下一个排列是 [1,2,3] ,因为 [3,2,1] 不存在一个字典序更大的排列。
给你一个整数数组 nums ,找出 nums 的下一个排列。
必须 原地 修改,只允许使用额外常数空间。

二、示例

示例一
示例二
示例三

三、提示

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

四、问题分析

这道题题目看起来相当长,但其实要表达的意思很简单,比如给了你一个125,你需要找到这三个数字组成的比他大且相邻的下一组数,所以应该是152.
如果是321,没有比他大的,那么返回最小的排列,即123.

五、解法

public void nextPermutation(int[] nums) {
         if(nums.length<2){
            return ;
        }
        int i=nums.length-1;
        while (nums[i]<=nums[i-1]){
            i--;
            if(i==0) {
                //此时为最大数,需返回这个数组的逆序
                int num = nums.length - 1;
                int left = 0;
                while (num > (nums.length - 1) / 2) {
                    int temp = nums[num];
                    nums[num] = nums[left];
                    nums[left] = temp;
                    num--;
                    left++;
                }
                //程序结束
                return;
            }
        }
        //此时遇到的是左边的数字小于右边的数字,
        // 需要向右寻找在左边数字与右边数字范围之内的最小数字
        int min=i;
        for(int j=i-1;j<nums.length;j++){
            if(nums[min]>nums[j]&&nums[j]>nums[i-1]){
                min=j;
            }
        }
            //先交换
            int temp = nums[min];
            nums[min] = nums[i - 1];
            nums[i - 1] = temp;
        //再对这个点后的数据进行从小到大的排序
        for(int j=i;j<nums.length;j++){
            for(int k=i;k<nums.length-1;k++) {
                if (nums[k] > nums[k + 1]) {
                    //交换位置
                    int a = nums[k];
                    nums[k] = nums[k + 1];
                    nums[k + 1] = a;
                }
            }
        }
        return ;
    }

六、代码分析

if(nums.length<2){
            return ;
        }

首先我们要考虑特殊情况:如果nums的长度为0或者1,此时没有下一个队列,我们直接return 即可。

int i=nums.length-1;
        while (nums[i]<=nums[i-1]){
            i--;
            if(i==0) {
                //此时为最大数,需返回这个数组的逆序
                int num = nums.length - 1;
                int left = 0;
                while (num > (nums.length - 1) / 2) {
                    int temp = nums[num];
                    nums[num] = nums[left];
                    nums[left] = temp;
                    num--;
                    left++;
                }
                //程序结束
                return;
            }
        }

接下来的ehile循环,则是为了找出数组从右向左第一个左边的数大于右边的数的索引,此时获得的索引就是i
案例
例如这个数组,获取到的i就是1
如果在这个while循环中,一直找不到左边的数大于右边的数这种情况,则说明这个数组没有下一个排列,(比他大的)也是一种特殊情况
在这里插入图片描述
也就是这种情况,根据题目规定,它的下一个排列应当是它的逆序数组
因此,我们使用一个while循环对数组进行逆序操作。然后return。

//此时遇到的是左边的数字小于右边的数字,
        // 需要向右寻找在左边数字与右边数字范围之内的最小数字
        int min=i;
        for(int j=i-1;j<nums.length;j++){
            if(nums[min]>nums[j]&&nums[j]>nums[i-1]){
                min=j;
            }
        }

此时已经找到我们需要的i索引,接下来需要找到从i到nums.length这段数组中的比nums[i-1]大,比nums[i]小的数,用min记录他的索引。
![在这里插入图片描述](https://img-blog.csdnimg.cn/30a4da4b5cbe4b33b3e07bc5281e5c5f.png

例如这两种情况,找到的min索引应当分别是2与1

if(min==i) {
            // 如果要交换的两个数字相邻将这两个位置进行交换
            int temp = nums[i];
            nums[i] = nums[i - 1];
            nums[i - 1] = temp;
        }else {
            //不相邻,先交换
            int temp = nums[min];
            nums[min] = nums[i - 1];
            nums[i - 1] = temp;
        }

然后进行我们将这两个数字进行交换

 //再对这个点后的数据进行从小到大的排序
        for(int j=i;j<nums.length;j++){
            for(int k=i;k<nums.length-1;k++) {
                if (nums[k] > nums[k + 1]) {
                    //交换位置
                    int a = nums[k];
                    nums[k] = nums[k + 1];
                    nums[k + 1] = a;
                }
            }
        }

然后为了保证我们找到的是满足条件的最小队列
我们将i索引后的数据进行从小到大排序
然后return。
至此,所有情况已经满足。

七、运行结果

在这里插入图片描述
水平有限,希望能帮到大家!

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值