原题
数组与哈希中等1 种解法

#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

查看原题

解题主线

  1. 从右向左找到首个 nums[pivot] < nums[pivot + 1],其右侧必为非递增后缀。
  2. 用后缀中最右侧且大于 pivot 的值交换,再反转后缀即可得到最小增量。

解法 1:枢轴交换 + 后缀反转

定位可增大的最右位置,以后缀中的最小更大值替换,再把后缀恢复为升序。

  • 时间复杂度: O(n)

  • 空间复杂度: O(1)

JAVA
final class Solution {
    public void nextPermutation(int[] nums) {
        // 枢轴右侧保持非递增;枢轴是最靠右的可增大位置。
        int pivot = nums.length - 2;
        while (pivot >= 0 && nums[pivot] >= nums[pivot + 1]) pivot--;
        if (pivot >= 0) {
            // 从末尾找到最小的更大值,使字典序增量尽可能小。
            int successor = nums.length - 1;
            while (nums[successor] <= nums[pivot]) successor--;
            swap(nums, pivot, successor);
        }
        // 反转非递增后缀得到升序;无枢轴时会反转整个数组。
        reverse(nums, pivot + 1, nums.length - 1);
    }

    private void reverse(int[] nums, int left, int right) {
        while (left < right) swap(nums, left++, right--);
    }

    private void swap(int[] nums, int left, int right) {
        int temporary = nums[left];
        nums[left] = nums[right];
        nums[right] = temporary;
    }
}

边界与易错点

  • 全数组非递增时 pivot 为 -1,应直接反转整个数组。
  • 交换对象必须是后缀中最右侧的大于 pivot 的元素。

整理来源

由旧仓库源码复核、去重并整理;展示代码已按 Java 21 语义修正明显问题。

  • medium/Q031_nextPermutation.java