「前端刷题」31. 下一个排列

187 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

题目

leetcode-cn.com/problems/ne…

实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列(即,组合出下一个更大的整数)。

如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。

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

 

示例 1:

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

示例 2:

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

示例 3:

**输入:**nums = [1,1,5] 输出:[1,5,1]

示例 4:

**输入:**nums = [1] 输出:[1]

 

提示:

  • 1 <= nums.length <= 100
  • 0 <= nums[i] <= 100

解题思路

  • 初始待交换位置-1倒序找第一个后 > 前位置,待交换位置
  • 倒序找第一个> 待交换位置的位置,与待交换位置交换
  • 待交换位置 + 1和数组尾部,向中间,双指针交换

代码

var nextPermutation = function(nums) {
    let s = (l, r, t) => (t = nums[l], nums[l] = nums[r], nums[r] = t), l = -1, r = nums.length
    for(let i = r; i--;)
        if (nums[i] > nums[i - 1]) l = i - 1, i = 0
    if (l !== -1) 
        for(i = r; i-- > l;)
            if (nums[i] > nums[l]) s(i, l), i = 0
    while (++l < --r) s(l, r)
};

结果

1.png

完整思路

  • 数组看成
  • 数怎样变大
    • 举例:数19高位是十位1低位是个位9
      • 高位 < 低位,交换高位低位91,数变大
    • 举例:数21高位是十位2低位是个位1
      • 高位 > 低位,再交换成12,数变小
  • 所以数变大,需找:
    • 高位 < 低位,然后交换
  • 倒序遍历数组,即从低位高位遍历。举例:[1, 4, 6, 5]
    • 高位 < 低位,然后交换
      • 6 > 5过,4 < 6交换,得[1, 6, 4, 5]
      • 1645 > 1465新数变大了。如果不要求下一个排列,这样做即可
  • 下一个排列怎么找?
    • 回到例子[1, 4, 6, 5]
    • 个位上的5比十位上的6更小,更适合与4交换
    • 4到数组尾部的最小值4交换 更好
    • 回想一下,4是怎样找到的呢?
      • 倒序遍历数组,找高位 < 低位
      • 这意味着4到数组尾部,都是高位 > 低位,是一个降序序列
      • 数组末尾就是最小值
    • 直接与数组末尾交换,行不行?
      • 回到例子:4 < 5,交换,得[1, 5, 6, 4],似乎可以
      • 改下例子:[1, 4, 6, 3],得[1, 3, 6, 4]变小
      • 所以,除了4到数组尾部的最小值,还需这个数比4
    • 所以,找下一个排列:
      • 倒序遍历数组,从最小值开始,找比4大的
  • 好像还不对?
    • 回到例子,交换45,得[1, 5, 6, 4]
    • 十位+个位64,显然46更好
    • 回想一下,4到数组尾部,都是高位 > 低位,是一个降序序列
      • 数组看成,降序序列最大。升序序列最小
  • 双指针交换
    • 4开始(4 + 1)和数组尾部向中间交换,将降序序列变升序序列即可
    • 如果本来就是降序序列,可声明左指针初始为-1,复用交换逻辑