题目描述

思路

代码
java
class Solution {
public void nextPermutation(int[] nums) {
int i = nums.length - 2;
// 1. 从后往前找第一个相邻的升序对 (nums[i] < nums[i+1])
while (i >= 0 && nums[i] >= nums[i + 1]) {
i--;
}
// 如果 i >= 0,说明找到了这样的数字,需要进行交换
// 如果 i < 0,说明整个数组是降序的,直接跳过交换步骤,进行全部反转即可
if (i >= 0) {
int j = nums.length - 1;
// 2. 从后往前找第一个大于 nums[i] 的数字 nums[j]
while (j > i && nums[j] <= nums[i]) {
j--;
}
// 3. 交换 nums[i] 和 nums[j]
swap(nums, i, j);
}
// 4. 将 i 之后的序列反转,使其变为升序(字典序最小)
reverse(nums, i + 1);
}
// 辅助方法:交换数组中两个元素
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
// 辅助方法:反转数组中从 start 开始到末尾的部分
private void reverse(int[] nums, int start) {
int left = start, right = nums.length - 1;
while (left < right) {
swap(nums, left, right);
left++;
right--;
}
}
}
复杂度分析
- 时间复杂度:O(N)O(N)O(N),其中 NNN 是数组的长度。我们最多只需要遍历数组两次(一次找 i,一次找 j),然后再反转一次数组末尾部分
- 空间复杂度:O(1)O(1)O(1),我们所有的交换和反转操作都是在原数组上直接进行的(原地修改),只使用了几个额外的整型变量,完全符合题意