實現 **下一個排列**:將數字序列重排為**字典序中比當前排列大的最小排列**。若不存在 (已是最大排列),重排為**最小排列** (升序)。**必須原地修改**,O(1) 額外空間。
例:[1,2,3]→[1,3,2], [3,2,1]→[1,2,3], [1,1,5]→[1,5,1]。
i,使得 nums[i] < nums[i+1]。i 右側 (遞減區間) 找**最右**的位置 j,使得 nums[j] > nums[i]。nums[i] 和 nums[j],然後將 i+1 到末尾 **反轉** (由遞減變遞增),得到最小增量。class Solution {
public:
void nextPermutation(vector& nums) {
int n = nums.size();
int i = n - 2;
// 1. 找拐點
while (i >= 0 && nums[i] >= nums[i+1]) --i;
if (i >= 0) {
int j = n - 1;
// 2. 找換位者
while (j > i && nums[j] <= nums[i]) --j;
swap(nums[i], nums[j]);
}
// 3. 反轉尾部 (i+1 到末尾)
reverse(nums.begin() + i + 1, nums.end());
}
};
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 (j > i && nums[j] <= nums[i]) j--;
swap(nums, i, j);
}
reverse(nums, i+1, n-1);
}
private void swap(int[] a, int i, int j) { int t=a[i]; a[i]=a[j]; a[j]=t; }
private void reverse(int[] a, int l, int r) { while(l
初始: [1, 3, 2] (字典序: 132)
1. 找拐點: i=0 (nums[0]=1 < nums[1]=3)
2. 找換位者: j=2 (nums[2]=2 > 1, 且最右)
3. 交換: [2, 3, 1]
4. 反轉尾部 (i+1=1 到末尾): [2, 1, 3] → 下一個排列 213 ✓
i=-1 時 reverse(begin, end) 即升序。nums[j] <= nums[i] (含等於),確保嚴格大於。i+1 到末尾,**包含 i+1**。[1,1,5]),因條件用 >= 和 <=。// 標準庫已實現
bool has_next = next_permutation(nums.begin(), nums.end());
// 返回 false 表示已是最大排列,且 nums 已重排為最小排列
// 完全符合題目要求,面試可先寫 STL 版,再手寫算法展示理解
Next Permutation 是「字典序生成」的核心算法,亦是組合生成、回溯剪枝、排序算法的基石。掌握其 **「拐點-換位-反轉」** 三步曲,不僅能解決 LeetCode 31,更能舉一反三實現:全排列生成、上一個排列、字典序第 k 個排列、組合/子集字典序迭代等。面試中手寫無 Bug 版本是基本功標配。