- 首先从后向前查找第一个顺序对 (i,i+1),满足 a[i] < a[i+1]。这样「较小数」即为 a[i]。此时 [i+1,n) 必然是下降序列。
- 如果找到了顺序对,那么在区间 [i+1,n) 中从后向前查找第一个元素 j 满足 a[i] < a[j]。这样「较大数」即为 a[j]。
- 交换 a[i] 与 a[j],此时可以证明区间 [i+1,n) 必为降序。我们可以直接使用双指针反转区间 [i+1,n) 使其变为升序,而无需对该区间进行排序。
class Solution {
public void nextPermutation(int[] nums) {
int i = nums.length - 2;
for (; i >= 0; i--) {
if (nums[i] < nums[i + 1]) break;
}
// while (i >= 0 && nums[i] >= nums[i + 1]) {
// i--;
// }
if (i >= 0) {
int j = nums.length - 1;
for (; j > i; j--) {
if (nums[i] < nums[j]) break;
}
// while (j >= 0 && nums[i] >= nums[j]) {
// j--;
// }
swap(nums, i, j);
}
reverse(nums, i + 1);
}
public void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
public void reverse(int[] nums, int left) {
int right = nums.length - 1;
while (left < right) {
swap(nums, left, right);
left++;
right--;
}
}
}
- 从排列的最末尾开始,找到第一个下降点,下降点的意义为这个点之前的序列无需改动。
- 然后,将后面的序列变为降序。
- 从下降点开始扫描,找到第一个下降点右边比它小的数字,交换即可。
public class Solution {
public List<Integer> previousPermuation(List<Integer> nums) {
int i = nums.size() - 2;
for (; i >= 0; i--) {
if (nums.get(i) > nums.get(i + 1)) break;
}
reverse(nums, i + 1);
if (i >= 0) {
int j = i + 1;
// while(nums.get(j) >= nums.get(i)) j++;
for (; j < nums.size(); j++) {
if (nums.get(j) < nums.get(i)) break;
}
swap(nums, i, j);
}
return nums;
}
public void swap(List<Integer> nums, int i, int j) {
int tmp = nums.get(i);
nums.set(i, nums.get(j));
nums.set(j, tmp);
}
public void reverse(List<Integer> nums, int left) {
int right = nums.size() - 1;
while (left < right) {
swap(nums, left, right);
left++;
right--;
}
}
}