上一篇: 算法随笔_5:接雨水-CSDN博客
题目描述如下:
整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。
- 例如,
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
的下一个排列。
必须 原地 修改,只允许使用额外常数空间。
==============================
解题思路:
根据题目要求已知一个整数的排列,需要求出按字典序的下一个排列。也就是说,找到下一个比当前这个数更大的数,且这两个数要紧挨着。例如下面这些按字典序的排列:
12345
12354
12435
12453
12534
...
54321
首先,我们需要保证数值是增大的。
其次,要保证数值是逐渐增大的。
如何保证第一点呢?很明显,降序的排列肯定比升序的排列数值大。
如何保证第二点呢?我们一起来看一下下面的分析:
上面第一行"12345",45是升序,那好,我们交换一下它俩让其变为降序54就可以了。
第二行"12354",从右往左看,54本身就是降序,说明最后两位的字典序排列已经是最大数了,我们需要继续往左找,发现是35升序,从这儿开始,我们需要把后三位重新排列,并且要保证数值是逐渐增大。重新排列的原则就是从后面两位中找一个比3大的最小数,然后剩下的两位需要按升序排列。这样就变成了12435。这个例子可能不明显,我们换一个例子,比如: 12398,它的下一个就是12839。这里大家可能有个疑问,刚才我们提到降序能保证数值增大,这里为什么又按升序排列?因为我们既要保证数值增大,而且要保证数值是逐渐增大的。既然,需要变动的后三位的高位已经变大,那这个数值一定比以前的数值大。但要保证逐渐增大,所以剩下的低位按照升序排列。
到此时,算法的雏形已经基本完成,给定一个排列,我们就可以按照这个原则去重新排列,即可得到下一个大数。
剩下的问题我们就需要考虑算法的效率问题了。算法涉及三个阶段:
第一阶段,从后往前找到需要变动的最少位数。这个问题一次迭代就能搞定。从后往前的数字需要不断变大,爬升,当发现数字变小,下降时,即找到了需要变动的位数。我们可以用一个指针p来做这一步。
第二阶段,需要从p指针所指数字num后面的位数中找一个比num大的最小数。然后两者交换。
第三阶段,我们需要把剩余的位数做升序排列。因为此时num后面的位数仍然保持降序,所以两两首尾交换,即可。
整个算法,我们只使用了一个tmpNum的变量,来临时存储交换时的值,因此符合题目要求的“原地”修改数组,只使用额外常数空间。算法时间复杂度为O(N),空间复杂度为O(1)。
以下是Python版的代码:
class Solution:
def swap(self, nums, i, j):
tmpNum=nums[i]
nums[i]=nums[j]
nums[j]=tmpNum
def nextPermutation(self, nums):
num_len=len(nums)
p1=0
p2=0
#第一阶段,从后往前找到需要变动的最少位数,p1指向降序的最高位,因此需要增大的是p1-1下标处
for i in range(1, num_len):
num2=nums[num_len-i]
num1=nums[num_len-i-1]
if num1<num2:
p1=num_len-i
break
if p1>0:
#如果p1>0, 第二阶段,需要从nums[p1-1]后面的位数中找一个比nums[p1-1]大的最小数
#如果p1==0 表示整个数组就是降序排列,直接跳过此步骤
for i in range(p1, num_len):
if nums[p1-1]>=nums[i]:
p2=i
break
self.swap(nums, p1-1, p2-1) #找到后交换位置
#第三阶段,我们把剩余的位数,做升序排列。因为本身就是降序列,所以两两首尾交换,即可。
cnt=int((num_len-p1)/2)
for i in range(cnt):
self.swap(nums, p1+i, num_len-i-1)
# 示例用法
solution = Solution()
#nums=[1,2,3,9,8,6,1]
#nums=[1,1,1]
#nums=[5,4,3,2,1]
nums=[1,5,1]
solution.nextPermutation(nums)
print(nums)
标签:排列,num,nums,len,算法,p1,升序,随笔
From: https://blog.csdn.net/m0_70494097/article/details/145140801