LeetCode-中等-31. 下一个排列
题目
引用自:LeetCode-中等-31. 下一个排列(如有侵权联系删除)
整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。
- 例如,
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
的下一个排列。
必须 原地 修改,只允许使用额外常数空间。
示例 1:
输入:nums = [1,2,3]
输出:[1,3,2]
示例 2:
输入:nums = [3,2,1]
输出:[1,2,3]
示例 3:
输入:nums = [1,1,5]
输出:[1,5,1]
提示:
1 <= nums.length <= 100
0 <= nums[i] <= 100
解题:
没什么好说的!做他,首先分析一下,因为想找到下一个更大的排列,那我们肯定是想要找到大于当前排列的大一丢丢的那个就好了,也就是交换其中部分数值所处的位置(*注意不只是交换两个数,因为只交换两个很多时候是不满足条件的,后面我们可以看到),为了到达这个目的我们首先可以想到,应该尽可能在把低位(靠近列表右边的那些)上的某个数值与其后面的某个数值交换,再调整某些位以实现上述要求:
例如:
[18, 0, 23, 25, 24, 22]
我们一眼看上去,第一步,会想着拿23
去和24
交换位置,而不是将18
和24
交换位置,因为23
相对18
而言,其处于更低的位。
整个过程而言:
首先我们会从低位看起,看24
与后面的某些数值交换后,是否能找到更大排列,但24
后面只有22
,交换之后排列变得更小了,并不可以。
接下来看25
,同样,与后面的24
,或者22
交换,排列会更小,也不可以。
接下来看23
,我们发现他与后面的24
或25
交换都会变得排列更大,但此时我们拿它和谁交换呢,当然是24
呀,因为24
是后面那些可以用来交换的两个个中,最小的那个。这样之后便得到[18, 0, 24, 25, 23, 22]
,但是很快我们便能发现这样交换之后,这并不是正解,因为23
与22
交换之后,我们还需要调整23
后面的那些值,才能得到正解[18, 0, 24, 22, 23, 25]
。
所以最后一步,当我们在把22
交换走以后,只需要对该位后面的数再排序一便就好了。
整体思想:
尽量保持高位不动,从低位去做一些改变使得能尽量找到大于当前排列,却又是最小的那组排列。
循环探索,从最低位开始逐步向高位走(也就是倒序遍历列表各个位),每次判断当前位置数值,与其后面的数值能否重新组合,生成更大的排列。在判断的过程中,每次尝试找到后面那些位中,大于当前位数值的值,却又是后面那些位中尽量小的。这个过程我们可以首先对后面的那些数值进行排序,然后正序逐一判断是否大于当前值,这样找到的第一个值就满足上述条件,然后将找到的该值与当前循环位的值交换,最后将当前循环位后面的那些数值做一个排序就好了。若是循环探索的过程中,一直没找到可以交换的值,说明该组排列本身就是最大的,那么依题,将该排列,reverse一下就可以得到最小排列了。
代码:
class Solution:
def nextPermutation(self, nums):
"""
Do not return anything, modify nums in-place instead.
"""
length = len(nums)
if length < 1:
return nums
i = length - 2
#从低位向高位探索
while i > -1:
#找第i位后面,是否有合适的值与第i位值交换
#整个过程因为要保证原地操作,所以需要额外的临时存储空间
temp1 = nums[i+1:]
temp1.sort()
switch_num = None
#排序后循环判断是否有合适值
for num in temp1:
if num > nums[i]:
#若是有的话就记录下来,并break
switch_num = num
break
#若是有合适的值,则定位该值的下标
if switch_num != None:
for j in range(i + 1, length):
if nums[j] == switch_num:
break
#找到该值后,交换,并把第i位后面的值排序
nums[i], nums[j] = nums[j], nums[i]
temp2 = nums[i + 1:]
temp2.sort()
for k in range(len(temp2)):
nums[i + 1 + k] = temp2[k]
return
i -= 1
nums.reverse()
测试:
class Solution:
def nextPermutation(self, nums):
"""
Do not return anything, modify nums in-place instead.
"""
length = len(nums)
if length < 1:
return nums
i = length - 2
#从低位向高位探索
while i > -1:
#找第i位后面,是否有合适的值与第i位值交换
#整个过程因为要保证原地操作,所以需要额外的临时存储空间
temp1 = nums[i+1:]
temp1.sort()
switch_num = None
#排序后循环判断是否有合适值
for num in temp1:
if num > nums[i]:
#若是有的话就记录下来,并break
switch_num = num
break
#若是有合适的值,则定位该值的下标
if switch_num != None:
for j in range(i + 1, length):
if nums[j] == switch_num:
break
#找到该值后,交换,并把第i位后面的值排序
nums[i], nums[j] = nums[j], nums[i]
temp2 = nums[i + 1:]
temp2.sort()
for k in range(len(temp2)):
nums[i + 1 + k] = temp2[k]
return
i -= 1
nums.reverse()
if __name__=='__main__':
print('测试1:')
a = [4, 2, 0, 2, 3, 2, 0]
s = Solution()
s.nextPermutation(a)
print('输入:nums = [4, 2, 0, 2, 3, 2, 0]')
print('输出:',a)
print('\n测试2:')
a = [1, 3, 2]
s.nextPermutation(a)
print('输入:nums = [1, 3, 2]')
print('输出:', a)
print('\n测试3:')
a = [4, 3, 2, 1]
s.nextPermutation(a)
print('输入:nums = [4, 3, 2, 1]')
print('输出:', a)
总结:
本身以为很简单,结果结果,哎,错了好几遍,耽误好一会,思维还是要缜密一点才行呀,不可马虎大意。