本人一直在努力地积累Leetcode上用Python实现的题,并且会尽力讲清每道题的原理,绝不像其他某些博客简略地带过。
如果觉得讲的清楚,欢迎关注。
实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须原地修改,只允许使用额外常数空间。
以下是一些例子,输入位于左侧列,其相应输出位于右侧列。1,2,3
→ 1,3,2
3,2,1
→ 1,2,3
1,1,5
→ 1,5,1
思路:我采用的是升序倒置法,具体:
下一个排列,其实本质上找的是下一个比当前数字大的数。当然,最后一种排列,也就是3,2,1这种找的是第一个。
123,下一个紧挨着123且稍稍大于123的数是132。也就是说我们要做一些调整,让我们当前数字增加,但同时增加幅度要最小。
本着这样的思路,当然是从后往前遍历,因为尾部的权重比较低(个位,十位。。。),改变起来增加的小。如果我们从后往前遍历,遍历的值都一直在增加,也就是如果一直升序的话,我们不可能说交换这个升序空间内的两个值来达到增加的目的。
比如465321,从后往前遍历到3之前,123是升序空间,我们不可能操作2个数字交换达到增值。
于是我们得找到第一个断点,在这个例子中就是4。断点即第一次前面的数比后一位数大了。找到这个断点,我们交换的其中一个目标就确定了,于是我们要找另一个交换目标?找谁合适呢?找3,那么整体减小;找6,那么整体确实增加,但好像不是最优;答案是找5,5也是从尾部开始数第一个比4(交换目标)大的数。(至于为什么从尾部遍历,其实是我们想降低交换带来的权重变化)好,于是我们的整体变成了564321。这个564321还不是最终答案,因为我们发现我们可以对5以后的所有数字进行排序,变成512346。这时才是我们要找的结果!
至于654321这种,直接判断它的升序空间末位置(6)的下一位为空,则返回一个123456(完全逆序)。
class Solution:
def nextPermutation(self, nums):
"""
:type nums: List[int]
:rtype: void Do not return anything, modify nums in-place instead.
"""
i = len(nums) - 1
if len(list(set(nums))) != 1:
#先从尾部升序结束的点
while i - 1 >= 0:
if nums[i] <= nums[i - 1]:
i = i - 1
else:
break
#如果前面还有至少一个位置
if i - 1 >= 0:
j = i - 1
t = len(nums) - 1
#从后往前找第一个大于j位置上的数
while nums[t] <= nums[j]:
t -= 1
nums[t], nums[j] = nums[j], nums[t]
a = sorted(nums[i:])
a_index = 0
#因为我不知道python分段排序的方法,于是就手动排序
#以下是对nums的排序
for index in range(i, len(nums)):
nums[index] = a[a_index]
a_index += 1
#没有位置则sort
else:
nums.sort()
反思总结:排列,实际上是一组有大小顺序的排列数。