LeetCode Hot100 31.下一个排列

文章目录

题目描述

整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。

例如,arr = 1,2,3 ,以下这些都可以视作 arr 的排列:1,2,31,3,23,1,22,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 = 1,2,3

输出:1,3,2

示例 2:

输入:nums = 3,2,1

输出:1,2,3

示例 3:

输入:nums = 1,1,5

输出:1,5,1

提示:

1 <= nums.length <= 100

0 <= numsi <= 100

题目解法

本题实质上使用的解法应当是双指针+贪心算法的应用。

本题的重点在于位置带来的权重与数字大小带来的权值之间的平衡。

要获得下一个最大排列,最简单的想法就是把前面的"小数"与后面的"大数"相交换。同时小数越靠右越好,大数越小越好。

这是因为小数越靠右权重就越小,所以这个位置换上大数后影响也就越小。

大数越小,造成的影响也就越小。

有了这个思想,我们令大数指针为 i ,小数指针为 j。大数指针从右向左寻找,这是因为为了让大数尽量靠近右边。

当局部出现从左向右递减数列时,我们必须跳过。

这是因为局部此时已经是最大情况了,想要更大不可能。只能跳过。

所以得到大数指针如下:

java 复制代码
int i = nums.length - 2;
        while (i >= 0 && nums[i] >= nums[i + 1]) {
            i--;
        }

但是如果整个数组都是递减数组,那么 i 的值将会是-1。这种情况直接翻转整个数组即可。因此在此处用 if 划分出不同的情况。

当 i >= 0时,就说明此时的地址指针有效。我们再去寻找小数指针 j 。

小数指针同样从右向左寻找。一是因为右边位置权值小,二是因为右边的大数指针刚刚经历过递减数列,找到小数的循环次数少。

java 复制代码
if (i >= 0) {
            int j = 0;
            while (j < nums.length && nums[i] >= nums[j]) {
                j++;
            }
            swap(nums, i, j);
        }

找到之后交换大数和小数的位置。

然后反向原大数指针位置后一位置的所有数列。这是因为后面跳过的都是递减数列,reverse之后变成了递增数列,整体变小。

完整代码

java 复制代码
class Solution {
    public void nextPermutation(int[] nums) {
        int i = nums.length - 2;
        while (i >= 0 && nums[i] >= nums[i + 1]) {
            i--;
        }
        if (i >= 0) {
            int j = nums.length - 1;
            while (j >= 0 && nums[i] >= nums[j]) {
                j--;
            }
            swap(nums, i, j);
        }
        reverse(nums, i + 1);
    }

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

    public void reverse(int[] nums, int start) {
        int left = start, right = nums.length - 1;
        while (left < right) {
            swap(nums, left, right);
            left++;
            right--;
        }
    }
}
相关推荐
zephyr0543 分钟前
动态规划-最长上升子序列问题
算法·动态规划
闪电悠米1 小时前
力扣hot100-56.合并区间-排序详解
数据结构·算法·leetcode·贪心算法·排序算法
卡提西亚2 小时前
leetcode-1438. 绝对差不超过限制的最长连续子数组
算法·leetcode·职场和发展
Java面试题总结3 小时前
LeetCode 93.复原IP地址
算法·leetcode·职场和发展·.net
从零开始的代码生活_3 小时前
C++ 多态详解:虚函数、动态绑定、抽象类与虚表原理
开发语言·c++·后端·学习·算法
泷寂4 小时前
最小生成树 (MST基础)
算法
Daniel_1234 小时前
数组——总结篇
算法
不懒不懒4 小时前
【针对路面识别数据集,结合三轴加速度标准化数据及多路面识别需求,以下是算法选择与处理方案】
算法
Reart4 小时前
Leetcode 121. 买卖股票的最佳时机(717)
后端·算法
会编程的小孩5 小时前
初识数据类型以及变量定义
数据结构·算法