题目:
实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须原地修改,只允许使用额外常数空间。
以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1
来源:力扣(LeetCode)
解:
这道题描述的是,数值序列下一个大的,也就是重排后跟原值的差值最小的。我们知道,降序序列值最大不需要改动,要获得大的,就要改动非降序序列。下一个大的肯定是从后面小的位进行开始调换。比如123,我们肯定不会去换1高位,而是从后往前看,把低位23换成32,就得到下一个大的。
从最低位向高位扫描,获得需要交换的位置(非降序的两个值),然后找到比该位更低位中最小的值(同时比交换的值大)调换,然后将该位后面的值按升序排列,比如12365543872,那么显然是3需要调换成7,那么后续低位就成了7832,显然还不是我们要的,因为差值不是最小,最小差值应该是使得后续低位总值最小,也就是升序序列,7238。这样就能保证调换差值控制在最小,也就是找到下一个大的序列。
时间复杂度:O(n);空间复杂度:O(1)。
import java.util.Arrays;
class Solution {
public void nextPermutation(int[] nums) {
//找非降序的调换位置
for(int i=nums.length-1;i>0;i--){
if(nums[i]>nums[i-1]){
int j=i+1;
//找低位最小调换位置
for(;j<nums.length;j++){
if(nums[j]<=nums[i-1]){
break;
}
}
int t=nums[i-1];
nums[i-1]=nums[j-1];
nums[j-1]=t;
int a=i,b=nums.length-1;
//后续低位最小化,即升序排列
while(a<=b){
t=nums[a];
nums[a]=nums[b];
nums[b]=t;
a++;
b--;
}
return;
}
}
//没找到,即降序数组,升序返回
Arrays.sort(nums);
}
}