zentan66 / daily-coding

日常手写算法,编程题
0 stars 0 forks source link

LeetCode-下一个排列「数组」 #3

Open zentan66 opened 3 years ago

zentan66 commented 3 years ago

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

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

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

其实就是找出指定数字的下一个最大的数,例如123的下一个是132

zentan66 commented 3 years ago

代码

function nextPermutation(nums) {
  let i = nums.length - 2 // 向左遍历,i从倒数第二开始是为了nums[i+1]要存在
  while (i >= 0 && nums[i] >= nums[i + 1]) {
    // 寻找第一个小于右邻居的数
    i--
  }
  if (i >= 0) {
    // 这个数在数组中存在,从它身后挑一个数,和它换
    let j = nums.length - 1 // 从最后一项,向左遍历
    while (j >= 0 && nums[j] <= nums[i]) {
      // 寻找第一个大于 nums[i] 的数
      j--
    }
    ;[nums[i], nums[j]] = [nums[j], nums[i]] // 两数交换,实现变大
  }
  // 如果 i = -1,说明是递减排列,如 3 2 1,没有下一排列,直接翻转为最小排列:1 2 3
  let l = i + 1
  let r = nums.length - 1
  while (l < r) {
    // i 右边的数进行翻转,使得变大的幅度小一些
    ;[nums[l], nums[r]] = [nums[r], nums[l]]
    l++
    r--
  }
  return nums
}

思路

  1. 倒序查找,直到前一个元素(a)小于后一个元素为止
  2. 再从上述步骤的元素(a)的后续集合中查找到比元素(a)大的元素(b)的索引
  3. 交换元素(a)和(b)
  4. 上述步骤执行后,元素(b)后就是一个倒序集合
  5. 将集合翻转,返回结果即可

举例

给定数组[5,4,7,5,3,2]

  1. 执行步骤1,查到索引i等于1
  2. 在[7,5,3,2]中找到比4大的数字,也就是5=>索引j等于3
  3. 交换之后是[5,5,7,4,3,2]
  4. 然后[7,4,3,2]翻转就是[2,3,4,7]