Lever's Castle

31. 下一个排列

April 15, 2020

https://leetcode-cn.com/problems/next-permutation/

解:

func nextPermutation(nums []int)  {
    if len(nums) <= 1 {
        return
    }

    i := len(nums) - 2
    for ; i >= 0; i-- {
        if nums[i] < nums[i+1] {
            j := i + 1
            for j + 1 < len(nums) {
                if nums[i] >= nums[j + 1] {
                    break
                }
                j++
            }
            nums[i], nums[j] = nums[j], nums[i]
            break
        }
    }
    k := len(nums) - 1
    i++
    for i < k {
        nums[i], nums[k] = nums[k], nums[i]
        i++
        k--
    }
}

题目不太好理解,看了几遍才搞明白是啥意思。这种题目描述也不好描述,我觉得可以把它类比成一个 n 位的数字来看,数组的最后一位是这个数字的个位,倒数第二位是数字的十位,以此类推。而所求的是,调整该数字的其中两位数字,使其恰好比原来大一些(数字的所有组合升序排序后,所求数字是当前数字的下一个)。当已经是降序的数组时(即在数字的所有组合升序排序后的最后一个),返回升序的数组(即在数字的所有组合升序排序后的第一个)。

我们从数组的最后一位开始遍历,找到前一位比后一位小的情况,并进行交换。交换时需要注意的是,并不是直接交换前后相邻的两位,而是要交换后面数字中比当前数字恰好大的那个数字,这样的交换才能保证交换后的结果最接近原数。交换完之后还需注意的是,此时交换位置后面的数字应该是一个降序的数字列表,在后面这列数字范围内,这显然是所有组合中最大的情况,而为了保证交换后的数字尽可能接近原数,我们需要对这节数字进行反转,变成最小的情况。同时这里也兼容了数组本身就是降序的情况。


Lever

痕迹
没有过去,就没法认定现在的自己