LeetCode Hot100 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 的下一个排列。

必须 原地 修改,只允许使用额外常数空间。

示例 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--;
        }
    }
}
相关推荐
其实防守也摸鱼11 小时前
个人学习 Pwn 思路:从基础到漏洞利用的进阶路径
大数据·前端·人工智能·chrome·算法·安全·网络安全
Nuanyt12 小时前
LeetCode Hot 100 链表专题(五)· 2 题(Java)
java·算法·leetcode·链表
w_zero_one15 小时前
递归算法(一)
java·开发语言·算法
圣保罗的大教堂15 小时前
leetcode 3736. 最小操作次数使数组元素相等 III 简单
leetcode
文丑颜不良啊16 小时前
LeetCode1881~1990题目解析
java·leetcode
风影同志7832416 小时前
20 个比特能装下多少行情?——实测拆解 Kronos 的 K 线分词器
算法
写的都是BUG17 小时前
APK 里的钥匙,一直就放在门口:聊聊加固真正该做什么
前端·算法
lsc_blog17 小时前
年底还在招的岗位,先确认缺口和到岗要求
git·缓存·ci/cd·职场和发展·github
地平线开发者17 小时前
CLIP 的零样本分类:一组文本如何变成图像分类器?
算法