下一个排列
描述
中等
实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须原地修改,只允许使用额外常数空间。
示例
以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1
解题
让我们找出这几个数中排序出的所有的数(全排列)中,刚好比当前数大的数
-
如果一个数是最大的数,那么组成这个数的数字肯定是依次减小的,比如
321
,432
,变成逆序就变成了下一个数,也就是最小的数 -
如果一个数是最小的数,那么组成这个数的数字肯定是依次增大的,比如
123
和234
,那么下一个数就是最后两位进行交换,得到132
和243
-
如果一个数既不是最大的数,也不是最小的数,如
13542
,从后往前找第一次正序变大的两个数,如3
和5
,然后得到前面一个数3
,将3
后面的数542
反转得到递增的245
,再将3
和245
中大于3
且最小的数,即4
,交换得14235
。由于3
和5
是从后往前的第一次正序,那么5
后面可能存在比5
小比3
大的数,至少,在3
后面,肯定有一个大于3
的数,即5
,来满足大于3
的条件
from typing import List
class Solution:
def nextPermutation(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
# 从后往前寻找第一次出现正序的位置,k为出现的正序两个数字中前一个数字的下标
k = -1
for i in range(len(nums) - 1, 0, -1):
if nums[i - 1] < nums[i]:
k = i - 1
break
# 数字全为逆序,当前值为最大值,直接逆序变为最小值
if k == -1:
nums.reverse()
return
# 将后面k个数逆序
nums[k + 1:] = nums[:k:-1]
# 交换
# 由于后面的数已经是正序,第一个大于nums[k]的数就是合适的数
for i in range(k + 1, len(nums)):
if nums[k] < nums[i]:
nums[k], nums[i] = nums[i], nums[k]
break
if __name__ == '__main__':
nums = [1, 2, 3]
print(nums)
Solution().nextPermutation(nums)
print(nums)
Solution().nextPermutation(nums)
print(nums)
Solution().nextPermutation(nums)
print(nums)
Solution().nextPermutation(nums)
print(nums)
Solution().nextPermutation(nums)
print(nums)