返回

LeetCode 31:下一个排列(双指针法)

前端

LeetCode 31:下一个排列

题目

给定一个排列整数数组 nums,编写一个函数对其进行重新排列,使其变为下一个字典序更大的排列。如果不存在下一个更大的排列,则将数组重新排列为第一个排列。

示例 1:

输入:nums = [1,2,3]
输出:[1,3,2]

思路 1:双指针法

  1. 查找降序子序列的末尾: 从后往前遍历 nums,找到第一个降序子序列的末尾元素 nums[i]。如果不存在降序子序列,则说明当前排列已经是最大的排列,返回第一个排列。
  2. 查找大于 nums[i] 的最小元素:i 开始,从后往前遍历 nums,找到第一个大于 nums[i] 的元素 nums[j]
  3. 交换 nums[i]nums[j] 交换 nums[i]nums[j],使降序子序列末尾的元素变大。
  4. 反转 nums[i+1:] nums[i+1:] 是一个降序子序列,将其反转可以得到下一个最大的子序列。
  5. 返回重新排列的 nums 返回重新排列后的 nums 数组。

代码:

/**
 * @param {number[]} nums
 * @return {void} Do not return anything, modify nums in-place instead.
 */
const nextPermutation = (nums) => {
  if (nums.length < 2) return;

  // 1. 查找降序子序列的末尾
  let i = nums.length - 2;
  while (i >= 0 && nums[i] >= nums[i + 1]) i--;

  // 如果不存在降序子序列,返回第一个排列
  if (i < 0) {
    nums.sort((a, b) => a - b);
    return;
  }

  // 2. 查找大于 nums[i] 的最小元素
  let j = nums.length - 1;
  while (nums[j] <= nums[i]) j--;

  // 3. 交换 nums[i] 和 nums[j]
  const temp = nums[i];
  nums[i] = nums[j];
  nums[j] = temp;

  // 4. 反转 nums[i+1:]
  const reversed = nums.slice(i + 1).reverse();
  nums.splice(i + 1, nums.length - i - 1, ...reversed);
};