Description
31. 下一个排列
难度中等1457
实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列(即,组合出下一个更大的整数)。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须原地修改,只允许使用额外常数空间。
示例 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]
Solution
以 [1,2,3] 为例子,其排列共有:1,2,3 -> 1,3,2 -> 2,1,3 -> 2,3,1 -> 3,1,2 -> 3,2,1 共六种排列,1,3,2 由 1,2,3 变换而来,而 3,2,1 的下一个排列为 1,2,3。
解法来源于 Leetcode 官方:
解题思路:
1、我们需要将一个左边的「较小数」与一个右边的「较大数」交换,以能够让当前排列变大,从而得到下一个排列。
2、同时我们要让这个「较小数」尽量靠右,而「较大数」尽可能小。当交换完成后,「较大数」右边的数需要按照升序重新排列。这样可以在保证新排列大于原来排列的情况下,使变大的幅度尽可能小。
以 nums=[1,2,1,0,5,2] 为例,其下一个排列为 [1,2,1,2,0,5]
1、在 nums=[1,2,1,0,5,2] 中找到左边「较小数」的 0,和右边「较大数」2,满足「较小数」的尽量靠右,「较大数」尽可能地小。
2、交换 0 和 2 得 [1,2,1,2,5,0],然后重新排序 2 右边的数,即得到 [1,2,1,2,0,5]
具体代码解法:
1、从数组nums后面向前遍历,找到一个顺序对 [i, i + 1],满足 nums[i] < nums[i+1],较小的数为 nums[i],此时 [i+1, n] 的序列必定是下降的序列。
2、如果找到了顺序对 [i, i+1],那么在区间 [i+1, n) 中,从后向前遍历,找到第一个元素 j,满足 nums[j] > nums[i],此时「较大数」为 nums[j],
3、交换 i 和 j 的位置,然后按照升序的顺序重新排列区间[i, n),如果在步骤1中,没有找到顺序对,此时数据 nums 必定是降序的顺序,那么重新按照升序的顺序排列数据 nums
代码思想:
class Solution {
public void nextPermutation(int[] nums) {
int cur = nums.length - 2; // 从数组末尾向前遍历,寻找第一个小于右边
int next = nums.length - 1; // 从数据末尾向前遍历,寻找第一个大于 cur 的数
while (cur >= 0 && nums[cur] >= nums[cur + 1])
cur --;
// 不存在下一个更大的排列的情况
if ( cur < 0){
Arrays.sort(nums);
return;
}
// 存在下一个更大排列的情况
while (nums[next] <= nums[cur])
next --;
swap(nums, cur, next);
Arrays.sort(nums,cur + 1, nums.length);
}
public void swap(int[] nums, int i, int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
