题目地址
整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。
例如,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
解题思路
解释:
字典序: 也就是序列全部的排列组合
下一个更大的: 比如 [1,2,3](123) 下一个更大的就是 [1,3,2](132)
以下解题思路参考:地址
解题思路:
- 首先需要从后往前找, 因为 位数是 (… 万千百十个)这样子的, 要从个位往上找(从右向左)
- 以 123(最小的数)为例。 逆着找 3(个位) > 2 十位 ,则直接进行交换 132 就是最小的
- 132, 逆着找(右向左), 1(百位) < 3(十位) 则 进行交换 这时候需要用 十位,个位当中最小的替换,就成了231
- 231 显然不是最接近 132的, 需要将 十位,个位逆序。因为 第三步中间判断到 1(百位了),说明 个位 < 十位(2 < 3), 百位 < 十位(1 < 3), 所以将剩下的 十位,各位逆序,才能是最小的。 变成 213
- 此时 213. 逆着找 1 小于 3, 那就直接 变为 2 31
- 此时 231. 逆着找 2 小于 3,需要寻找 比2 大一点的数(最接近2的) 变为 321, 然后 反转312
- 312 变为 321
- 321 是最大的了, 低位比高位大的。 所以全部反转 123
再举一个例子: 452631
- 首先找到低位比高位大的 2 6
- 从 2 后面调出来 最接近2的,需要大于2. 也就是3, 交换变为 453621
- 低位的数字逆序 变为 453126(为什么能直接逆序后面的数字,因为既然选择到2 6,和3 ,2 一定 大于等于3之后的数,如果不大于,那就选择3之后的数了)
总结一下,数组num长度n,下标i范围为0~n-1,从数组的n-1位置出发,往下标为0的方向查找(逆序遍历),找到num[i-1]小于num[i]的值,那么就重点关注这个num[i-1]的值。
在这基础上,再来一次逆序遍历查找比num[i-1]大的值,且是这些值里的最小值(也就是说,找到一个值,该值比num[i-1]大,但也是所有比num[i-1]大的值里面的最小值),那么就把该值与num[i-1]两值调换。
最后,反转数组里下标为i到n-1的值。即将num[i],num[i+1],…,num[n-1],num[n],反转为num[n],num[n-1],…,num[i+1],num[i]。
代码实现:
class Solution:
def nextPermutation(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
def reverse(low, high):
""" 用来进行反转 """
while low < high:
nums[low], nums[high] = nums[high], nums[low]
low, high = low + 1, high - 1
# 写代码实现
n = len(nums)
for i in range(n-1, 0, -1):
# 如果高位小于低位数字
if nums[i-1] < nums[i]:
# 完成 高位 与最接近且大于它的低位进行交换, 最接近的低位,一定是逆序遍历大于它的第一个数
for j in range(n-1, 0, -1):
if nums[j] > nums[i-1]:
nums[i-1], nums[j] = nums[j], nums[i-1]
break
# 再将高位往后的低位进行逆序
reverse(i, n-1)
break
else:
# 正常循环结束,则说明是最大的直接反转
reverse(0, n-1)//像示例2那样的特殊情形
注:for i in range(n-1, 0, -1)表示从n-1到0(不包括0),步长为-1
平时没有写第三个值,是因为默认步长为1
如:range(1,4,2):从1到4,步长为2,即1,3