LeetCode 31:下一个排列(Next Permutation)------ 完整题解笔记 ✅
🔗 题目链接
👉 https://leetcode.cn/problems/next-permutation/
📖 内容概要
给定一个整数数组 nums,表示一个排列,要求 原地修改 ,将其变为 字典序中下一个更大的排列 。
若不存在下一个更大排列,则返回最小的排列(升序)。
✅ 时间复杂度 O(n)
✅ 空间复杂度 O(1)
✅ 面试高频题
💡 解题思路(核心)
一、关键思想
- 从右往左看:
- 如果右侧一直递增(左 < 右),说明这部分已经是最大状态
- 只有当某个位置"变小"时,才可能变得更大
二、三步法
✅ 第一步:从右往左找第一个"降序数"
java
while (i >= 0 && nums[i] >= nums[i + 1]) i--;
找到的 nums[i] 是:
从右往左第一个小于它右边邻居的数
含义:
nums[i]是 可以变大的最低位i右侧是 最大后缀
✅ 第二步:找 nums[i] 右边最小的比它大的数
java
while (j > i && nums[j] <= nums[i]) j--;
swap(nums, i, j);
- 在
i右侧 - 找 刚好比
nums[i]大的最小数 - 交换
👉 保证:
- 排列变大
- 增幅最小
✅ 第三步:反转 i 右侧部分
java
reverse(nums, i + 1, n - 1);
- 交换后右侧仍是降序
- 反转后得到 最小后缀
- 构成 下一个排列
三、特殊情况
| 情况 | 说明 |
|---|---|
i < 0 |
已是最大排列 |
| 处理方式 | 反转整个数组 |
📌 举例说明(非常重要)
示例数组
text
nums = [1, 3, 5, 4, 2]
Step 1️⃣:找第一个降序数
从右往左:
2 < 4 < 5 > 3
找到:
i = 1
nums[i] = 3
✅ 3 是第一个"右边还有更大数"的数
Step 2️⃣:找右边最小的大数并交换
i = 1,右边是:
[5, 4, 2]
从右往左找第一个大于 3 的数:
4
交换 3 和 4:
[1, 4, 5, 3, 2]
Step 3️⃣:反转 i 右侧部分
反转 [5, 3, 2]:
[2, 3, 5]
最终结果:
[1, 4, 2, 3, 5]
✅ 这就是 下一个排列
✅ 对比验证
| 排列 | 字典序 |
|---|---|
| 原排列 | 1 3 5 4 2 |
| 下一个 | ✅ 1 4 2 3 5 |
✅ AC 代码(Java)
java
class Solution {
public void nextPermutation(int[] nums) {
int n = nums.length;
int i = n - 2;
// 第一步:从右往左找第一个降序的位置
while (i >= 0 && nums[i] >= nums[i + 1]) {
i--;
}
// 第二步:交换
if (i >= 0) {
int j = n - 1;
while (i < j && nums[j] <= nums[i]) {
j--;
}
swap(nums, i, j);
}
// 第三步:反转
reverse(nums, i + 1, n - 1);
}
private void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
private void reverse(int[] nums, int i, int j) {
while (i < j) {
swap(nums, i++, j--);
}
}
}
⏱️ 复杂度分析
| 指标 | 复杂度 |
|---|---|
| 时间复杂度 | O(n) |
| 空间复杂度 | O(1) |
✅ 一句话总结
从右往左找到第一个"还能变大"的位置,把它换成右边最小的大数,再把后面变成最小后缀。
掌握这道题,就掌握了:
- 字典序排列
- 原地数组操作
- 指针边界控制