题干
31. 下一个排列
难度中等466收藏分享切换为英文关注反馈
实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须**原地**修改,只允许使用额外常数空间。
以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,3
→ 1,3,2
3,2,1
→ 1,2,3
1,1,5
→ 1,5,1
思路
排列的大小我们可以把它理解为把整个数组看作一个整数,如[1,2,3]可以把它看作整数123
而[1,3,2]就是比[1,2,3]更大的排列,因为132>123
若想只通过变换位置得到更大的排列需要做的就是把值更大的数字往前移(对于数组来说就是下标越小的数字权重越大)
所以题目要求的下一个排列,实际所求即为比原来排列大,而且与原排列最接近的一个排列。
也就是说本题要实现两个条件:
- 要让排列变大
- 作出的改动最小
对于第一个条件,若要让排列变大,只需要将较大的数字前移即可。
对于第二个条件,若要作出的改动小,则需要将改动的位置尽量处于数组末尾(末尾权重较小)
所以解决这道题的思路就可以如下方式进行:
从后往前遍历数组,下标为index
if nums[index] >= nums[index + 1]
我们要做的是将大数前移,而这里明显大数已经在前面,所以在这里不做任何操作,继续循环
else:
走到这个分支说明存在位于index后面的数字存在值比nums[index]大的
所以在这里我们找到exchange_index,使得
nums[exchange_index]是最接近nums[index]且比nums[index]大的值
这样将nums[exchange_index]与nums[index]互换保证变动较小。
同时,对于index后面的剩余数列,进行递增排序(保证变动较小)
break
Tips:
- 由于找到index时,说明index后面的数据为降序排列,所以要进行递增排序只需要对他们进行reverse操作
- 若整个数组都时降序排列,则对整个数组进行reverse操作(变为升序)
- python代码
class Solution:
def nextPermutation(self, nums: List[int]) -> None:
n = len(nums)
if n == 0:
return
for index in range(n - 2, -1, -1):
if nums[index] < nums[index + 1]:
self.reverse(nums, index + 1, n)
exchange_index = bisect.bisect_right(nums, nums[index], index + 1, n)
nums[index], nums[exchange_index] = nums[exchange_index], nums[index]
break
if index == 0:
self.reverse(nums, 0, n)
def reverse(self, nums, start, end):
end -= 1
while(start < end):
nums[start], nums[end] = nums[end], nums[start]
start += 1
end -= 1