实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须原地修改,只允许使用额外常数空间。
以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1
逻辑:
- 1837 1873 # 最简单的一种,直接互换
- 1873 3178 # 后面3位 873 是倒序的,没法再生成下一个元素,所以要把1来拿来,首先1 和 873 中最小的3 互换 变成 3 871 然后后面的871 按照增序排列变成178 综合就变成了3178
- 1783 1837
- 1583 1835
- 1983 3189
这道题想了挺久的,附上代码,注释在代码中:
class Solution(object):
def nextPermutation(self, nums):
"""
:type nums: List[int]
:rtype: None Do not return anything, modify nums in-place instead.
"""
length = len(nums)
pre = length - 2
after = length -1
while pre >= 0:
if nums[pre] < nums[after]:
temp = after
# 当temp小于数组当中最大的数时
while temp <= len(nums) - 1:
#如果找到了一个temp对应的数组值小于nums[pre],则将两个数互换再进行
if nums[temp] <= nums[pre]:
nums[pre],nums[temp-1] = nums[temp-1],nums[pre]
break
# 如果遍历到最后还没找到比nums[pre]小的数,那么就让最后一个数跟num[pre]互换位置再进行排序
# 如123549876 ==》 123569874,再排序
if temp == len(nums)-1 and nums[temp] > nums[pre]:
nums[pre], nums[temp] = nums[temp], nums[pre]
temp += 1
#排序
nums[pre+1:] = nums[:pre:-1]
break
else:
#往前移
pre -= 1
after -= 1
if pre == -1:
#如果是54321类型,转换成12345
nums[:] = nums[::-1]
在评论区找到了代码逻辑更加清晰简洁的代码:
代码思路:
用nums = [1,3,5,7,6,4,2,1]来做示范吧. 首先,第一个指针从队尾开始向前遍历(i = len(nums) - 2),判断一下i+1与i的大小关系.在遍历到5之前,一直是nums[i]>nums[i+1]. 在第一个指针指向5时,第二个指针同样从队尾出发,因为在逆向遍历到i之前,一直是升序的,刚开始nums[j] <= nums[i]是一直满足的,当j停止移动时,j指向的数字是刚刚好大于nums[i]的,在例子中,j刚好指向6.
将nums[i]与nums[j]进行互换.此时nums = [1,3,6,7,5,4,2,1].此时6之后的数字是降序的,所以将6之后数字进行反转,才能达到题目要求"刚好大于原序列的效果",然后将nums[i+1:]进行反转即可.
class Solution:
def nextPermutation(self, nums):
"""
:type nums: List[int]
:rtype: void Do not return anything, modify nums in-place instead.
"""
i = len(nums) - 2
while i >= 0 and nums[i+1]<=nums[i]:
i -= 1
if i >= 0:
j = len(nums) - 1
while j >= i and nums[j] <=nums[i]:
j -= 1
self.swap(nums,i,j)
self.reverse(nums,i+1)
def reverse(self, nums,start):
i = start
j = len(nums) - 1
while i < j :
self.swap(nums,i,j)
i += 1
j -= 1
def swap(self,nums,i,j):
temp = nums[i]
nums[i] = nums[j]
nums[j] = temp