本文目录
- 1 中文题目
- 2 求解方法:单次扫描法
- 2.1 方法思路
- 2.2 Python代码
- 2.3 复杂度分析
- 3 题目总结
1 中文题目
整数数组的一个 排列
就是将其所有成员以序列或线性顺序排列。
例如,arr = [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。
整数数组的 下一个排列
是指其整数的下一个字典序更大的排列。更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,那么数组的 下一个排列
就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。
对于数组arr = [1,2,3] ,该数组的所有排列按照字典顺序从小到大应该是:[1,2,3]、[1,3,2]、[2,1,3]、[2,3,1]、[3,1,2]、[3,2,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
的下一个排列。
注意: 必须 原地
修改,只允许使用额外常数空间
示例:
输入:nums = [1,2,3]
输出:[1,3,2]
输入:nums = [3,2,1]
输出:[1,2,3]
输入:nums = [1,1,5]
输出:[1,5,1]
提示:
- 1 ≤ n u m s . l e n g t h ≤ 100 1 \leq nums.length \leq 100 1≤nums.length≤100
- 0 ≤ n u m s [ i ] ≤ 100 0 \leq nums[i] \leq 100 0≤nums[i]≤100
2 求解方法:单次扫描法
2.1 方法思路
方法核心
- 使用单次扫描找到需要改变的位置
- 通过交换和反转实现原地修改
- 保证得到下一个字典序更大的排列
实现步骤
(1)寻找交换位置:
- 从右向左找第一个升序对
- 确定需要改变的最小范围
(2)寻找交换元素:
- 从右向左找第一个大于当前数的元素
- 确保交换后得到较小的增长
(3)重排后续元素:
- 反转交换位置后的所有元素
- 确保得到最小的可能值
方法示例
输入:nums = [1,2,3]
过程演示:
1. 初始状态:[1,2,3]
2. 找升序对:
从右向左扫描
找到2 < 3,i = 1
3. 找交换元素:
从右向左找到第一个大于2的数字
找到3,j = 2
4. 交换元素:
交换nums[1]和nums[2]
变成:[1,3,2]
5. 反转后续:
反转i+1到末尾的元素
最终结果:[1,3,2]
返回:[1,3,2]
2.2 Python代码
class Solution:
def nextPermutation(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
n = len(nums)
if n <= 1:
return
# 1. 从右向左找第一个相邻升序对(i,i+1)
# 即找到第一个nums[i] < nums[i+1]的位置i
i = n - 2
while i >= 0 and nums[i] >= nums[i + 1]:
i -= 1
if i >= 0:
# 2. 从右向左找第一个大于nums[i]的数
j = n - 1
while j > i and nums[j] <= nums[i]:
j -= 1
# 3. 交换i和j位置的数
nums[i], nums[j] = nums[j], nums[i]
# 4. 将i+1到末尾的数进行反转
# 如果i=-1,则反转整个数组
left = i + 1
right = n - 1
while left < right:
nums[left], nums[right] = nums[right], nums[left]
left += 1
right -= 1
2.3 复杂度分析
- 时间复杂度:O(n)
- 最多需要两次遍历
- 反转操作需要O(n/2)时间
- 空间复杂度:O(1)
- 只使用常数额外空间
- 原地修改数组
3 题目总结
题目难度:中等
数据结构:数组
应用算法:单次扫描法