下一个排列

155 阅读3分钟

31.下一个排列

1. 题目描述

整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。

例如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的下一个排列。

2. 题目示例

2.1 示例1

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

2.2 示例2

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

2.3 示例3

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

2.4 提示

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

3. 解题思路

3.1 算法过程

标准的 “下一个排列” 算法可以描述为:

  1. 从后向前查找第一个相邻升序 的元素对(i,j),满足A[i] < A[j]。此时[j,end)必然是降序
  2. [j,end)从后向前查找第一个满足A[i] < A[k]的k。
  3. A[i]A[k]交换
  4. 可以断定这时[j,end)必然是降序,逆置[j,end)使其升序
  5. 如果在步骤1找不到符合的相邻元素对,说明当前 [begin,end)为一个降序顺序,则直接跳到步骤4

3.2 可视化

  1. 以求12385764的下一个排列为例。

image.png 2. 首先从后向前查找第一个相邻升序的元素对(i,j)。这里 i=4j=5,对应的值为5,7

image.png 3. 然后在[j,end)从后向前查找第一个大于A[i]的值 A[k]。这里A[i]5,故A[k]6 image.png 4. 将A[i]A[k]交换。这里交换56

image.png 5. 这时[j,end)必然是降序,逆置[j,end),使其升序。这里逆置[7,5,4]

image.png 因此12385764的下一个排列就是12386457

4. 解题代码

4.1 go

func nextPermutation(nums []int)  {
    i,j,k := len(nums)-2,len(nums)-1,len(nums)-1

    //find: A[i]<A[j]
    for i>=0 && nums[i] >= nums[j]{
        i--
        j--
    }
    if i>=0{
        //find: A[i] < A[k]
        for nums[i] >= nums[k]{
            k--
        }
        //swap:A[i],A[k]
        nums[i],nums[k] = nums[k],nums[i]
    }
    //sort: 升序
    sort.Ints(nums[j:])
}

4.2 go

func nextPermutation(nums []int)  {
    i,j,k := len(nums)-2,len(nums)-1,len(nums)-1

    //find: A[i]<A[j]
    for i>=0 && nums[i] >= nums[j]{
        i--
        j--
    }
    if i>=0{
        //find: A[i] < A[k]
        for nums[i] >= nums[k]{
            k--
        }
        //swap:A[i],A[k]
        nums[i],nums[k] = nums[k],nums[i]
    }
    //reverse: A[j:end]  
    //比sort.Ints快点
    for l,r := j,len(nums)-1; l < r; l,r = l+1,r-1{
        nums[l],nums[r] = nums[r],nums[l]
    }
}