题目描述
整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。
例如,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
思考
寻找下一个排列的核心是找到“最小幅度的增大”,即通过最少的调整让排列变得更大。具体通过以下步骤实现:先找到需要调整的位置,再交换以增大数值,最后反转后续元素使整体最小化,从而得到字典序的下一个排列。
算法过程
-
找到第一个可调整的位置:
- 从数组末尾向前遍历(
i从n-2到0),寻找第一个满足nums[i] < nums[i+1]的索引minIndex。 - 这一步的意义:
minIndex是最右侧的“可以通过调整使排列增大”的位置(因为其右侧元素已按降序排列,无法再增大)。 - 若未找到(
minIndex = -1),说明数组是最大排列(如[3,2,1]),直接反转数组得到最小排列。
- 从数组末尾向前遍历(
-
交换以增大数值:
- 从数组末尾向前遍历,寻找第一个大于
nums[minIndex]的元素索引i,交换nums[minIndex]与nums[i]。 - 这一步确保了调整后的数值是“最小可能的增大”(选择最小的大于
nums[minIndex]的元素)。
- 从数组末尾向前遍历,寻找第一个大于
-
反转后续元素:
- 交换后,
minIndex右侧的元素仍为降序(因原右侧是降序,交换后仍保持降序特性)。 - 将
minIndex右侧的元素反转(从minIndex+1到n-1),使其变为升序,确保这部分是最小可能的排列。
- 交换后,
示例推导(以 nums = [1,3,2] 为例)
-
寻找 minIndex:
- 从末尾遍历:
i=1时,nums[1]=3不小于nums[2]=2;i=0时,nums[0]=1 < nums[1]=3,故minIndex=0。
- 从末尾遍历:
-
交换元素:
- 从末尾找第一个大于
nums[0]=1的元素,即nums[1]=3,交换后数组变为[3,1,2]。
- 从末尾找第一个大于
-
反转右侧:
minIndex=0右侧为[1,2],已为升序,无需反转。最终结果为[3,1,2]。
时空复杂度分析
- 时间复杂度:O(n),三次遍历(寻找
minIndex、寻找交换元素、反转右侧)均为线性时间,总时间与数组长度成正比。 - 空间复杂度:O(1),仅使用常数个变量,所有操作均在原数组上进行,满足“原地修改”和“常数空间”要求。
代码
/**
* @param {number[]} nums
* @return {void} Do not return anything, modify nums in-place instead.
*/
var nextPermutation = function(nums) {
const n = nums.length;
let minIndex = -1;
for (let i = n-2; i >= 0; i--) {
if (nums[i] < nums[i+1]) {
minIndex = i;
break;
}
}
if (minIndex === -1) {
nums.reverse();
return;
}
for (let i = n-1; i > minIndex; i--) {
if (nums[i] > nums[minIndex]) {
[nums[i], nums[minIndex]] = [nums[minIndex], nums[i]];
break;
}
}
let l = minIndex+1, r = n-1;
while (l < r) {
[nums[l], nums[r]] = [nums[r], nums[l]];
l++;
r--;
}
};
575

被折叠的 条评论
为什么被折叠?



