题目
实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须原地修改,只允许使用额外常数空间。
以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,5,4,3 →1,3,2,4,5
3,2,1 → 1,2,3
1,2,3 → 1,3,2
2,3,1 → 3,1,2
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/next-permutation
题目分析
这个题没有太多技巧,只要思维好点,能够想出解法,自然可以解决
上面四个测试用例是我精心挑选的,基本可以涵盖所有极端情况
我的技巧:
第一步,从末尾开始找最长倒序
第二步,交换
第三步,反转
下面举例说明技巧
例一 :1,2,5,4,3 →1,3,2,4,5
第一步,从末尾开始找到最长倒序5,4,3
第二步,2和3交换,1,3,5,4,2
第三步,反转5,4,2得到1,3,2,4,5
例二:3,2,1 → 1,2,3
第一步,从末尾开始找到最长倒序3,2,1
第二步,这种完全倒序情况不需交换
第三步,反转即可1,2,3
例三:1,2,3 → 1,3,2
第一步,从末尾开始找到最长倒序3
第二步, 2和3交换,1,3,2
第三步,反转2还是1,3,2
例四:2,3,1 → 3,1,2(我死在这个用例上一次)
第一步,从末尾开始找到最长倒序3,1
第二步, 这时候交换要注意了,1不可以和2交换,要从倒序中找到第一个可以和2交换的数,即3,交换后3,2,1
第三步,反转2,1得到3,1,2
代码
public class NextPermutation {
public static void main(String[] args) {
int[] nums = new int[]{2,3,1};
new NextPermutation().nextPermutation(nums);
for (int i :nums) {
System.out.print(i+" ");
}
}
public void nextPermutation(int[] nums) {
if(null==nums||nums.length<=1)return;
//从末尾开始找倒序
int i = nums.length-1;
int num = nums[i];
i--;
while(i>=0&&nums[i]>=num){
num = nums[i];
i--;
}
//如果i>=0,说明需要交换
if(i>=0){
//找出最合适的交换位置
int len = nums.length-1;
while(nums[i]>=nums[len]){
len--;
}
int temp = nums[i];
nums[i] = nums[len];
nums[len] = temp;
}
//反转 后面的元素
swap(nums,i+1,nums.length-1);
}
private void swap(int[]nums,int i,int j){
for(int m=i;m<=(i+j)/2;m++){
int temp = nums[m];
nums[m] = nums[j-m+i];
nums[j-m+i] = temp;
}
}
}
beat 100% perfect