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 <= nums[i] <= 100

题目解法

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

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

要获得下一个最大排列,最简单的想法就是把前面的“小数”与后面的“大数”相交换。同时小数越靠右越好,大数越小越好
这是因为小数越靠右权重就越小,所以这个位置换上大数后影响也就越小。
大数越小,造成的影响也就越小。

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

当局部出现从左向右递减数列时,我们必须跳过
这是因为局部此时已经是最大情况了,想要更大不可能。只能跳过。

所以得到大数指针如下:

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

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

当 i >= 0时,就说明此时的地址指针有效。我们再去寻找小数指针 j 。
小数指针同样从右向左寻找。一是因为右边位置权值小,二是因为右边的大数指针刚刚经历过递减数列,找到小数的循环次数少。

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

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

完整代码

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--;
        }
    }
}

你可能感兴趣的:(Leetcode刷题之路,leetcode,算法,职场和发展)