链接:https://leetcode-cn.com/problems/next-permutation/
题目描述:
思路:
1.特殊情况:给定的序列是降序排列,如[3, 2, 1];那么结果直接反转为[1,2,3]
2.题目要求 原地修改 -》 使用给的nums数组进行元素交换
下一个排列要满足:比当前序列尽可能的小 -》 很明显应该从后面依次向前挪动
a. 比当前序列小:从后往前查找(begin, end), 有 begin < i < j < end,满足nums[i] < nums[j], 交换两个数,结果一定小于原来的序列;如 12345 -> 12354
b. 尽可能的小:根据情况a找到大数和小数下标 i, j, 在区间[j, end)中从后往前查找第一个大于nums[i]的数 k, 交换这两个数,然后将新序列的[j, end)区间进行反转。
如: 124653 -》 125643 符合;
可证:[j, end) 单调递减的,因此nums[k](大于nums[i]的第一个数)与nums[i]交换后,一定也满足[j, end)单调递减,且 nums[i]的值一定大于原来的值
代码:
/*
从就往前遍历,找到第一个升序的相邻数列,记为i,j, 得区间[j, end)
在[j, end)区间中从后往前找到第一个nums[k] > nums[i], 交换,然后[j, end)升序
*/
public void nextPermutation(int[] nums) {
if (nums.length == 1) return;
int len = nums.length;
boolean flag = false;
for (int i = len - 1; i > 0; i--) {
if (nums[i - 1] < nums[i]) {
flag = true;
for (int j = len - 1; j >= i; i--) {
if (nums[j] > nums[i - 1]) {
swap(nums, i - 1, j);
break;
}
}
reverse(nums, i, len - 1);
}
if (flag) break;
}
if (!flag) {
reverse(nums, 0, len - 1);
}
}
private void reverse(int[] nums, int begin, int end) {
while (begin <= end) {
swap(nums, begin, end);
begin ++; end --;
}
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}