LeetCode_双指针_中等_31.下一个排列
1.题目
实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。必须原地修改,只允许使用额外常数空间。
示例 1: 输入:nums = [1,2,3] 输出:[1,3,2]
示例 2: 输入:nums = [3,2,1] 输出:[1,2,3]
示例 3: 输入:nums = [1,1,5] 输出:[1,5,1]
示例 4: 输入:nums = [1] 输出:[1]
提示: 1 <= nums.length <= 100 0 <= nums[i] <= 100
2.思路
(1)双指针 思路参考该。
想得到当前排列在字典序中下一个更大的排列,则需要将前面的“小数”与后面的”大数“进行交换,并且还要保证下一个数的增加幅度最小,这样就能得到符合条件的排列。为此需要: ① 从数组后面向前找第一个升序元素对 (nums[i], nums[i + 1]),即 nums[i] < nums[i + 1],其中从后向前找是为了尽量在低位上交换,以保证下一个数增加的幅度最小; ② 在 nums[i + 1…nums.length - 1] 中从后向前查找第一个大于 nums[i] 的值 nums[j],然后交换它们的值; ③ 最后将 nums[i + 1] ~ nums[nums.length - 1] 从降序变成升序即可,由于前面已经将 nums[i] 与 nums[j] (nums[i] < nums[j]) 进行了交换,即新得到的排列已经比原来的大,但为了保证增加的幅度最小,所以需要将 nums[i] 后面的序列变成降序。
3.代码实现(Java)
//思路1————双指针
class Solution {
public void nextPermutation(int[] nums) {
int i = nums.length - 2;
//从数组后面向前找第一个升序元素对(nums[i], nums[i + 1]),即 nums[i] < nums[i + 1]
while (i >= 0 && nums[i] >= nums[i + 1]) {
i--;
}
//若 i >= 0,则已经找到升序元素对
if (i >= 0) {
int j = nums.length - 1;
//在 nums[i + 1...nums.length - 1] 中从后向前查找第一个大于 nums[i] 的值 nums[j]
while (j >= 0 && nums[j] <= nums[i]) {
j--;
}
//交换 nums[i] 和 nums[j] 的值
swap(nums, i, j);
}
//将 nums[i + 1] ~ nums[nums.length - 1] 反转,即从降序变成升序
reverse(nums, i + 1);
}
//将 nums[start] ~ nums[nums.length - 1]反转
public void reverse(int nums[], int start) {
int i = start;
int j = nums.length - 1;
while (i < j) {
swap(nums, i, j);
i++;
j--;
}
}
//交换 nums[i] 和 nums[j] 的值
public void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
