31. 下一个排列
思路:实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。必须原地修改,只允许使用额外常数空间。
以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1
先来观察一个例子【76958643】这个数,我们要找下一个大的数,首先我们能想到的肯定是从右边下手,因为要求是下一个最大的数,可以看到,从右边开始看这个数,每一位都是递增的,所以如果交换最右边几个只会使数字更小,所以我们应该找到第一个递减的数,也就是5。
找到这个数之后我们考虑交换了,我们将5和6交换(6是右边第一个大于5的数),那么这时候高位5已经变大成6了,数字确实是变大了,但是到底是不是下一个最大呢?
显然不是,因为右边的数是递减的,我们需要把他再变小一点(因为高位5已经变成6,已经完全可以保证该数比原数大,现在要做的是使右边的数最小),我们直接将右边的数逆序即可。
public void nextPermutation(int[] nums) {
int i = nums.length-2;
while(i>=0&&nums[i+1]<=nums[i]){
i--;//找到开始递减的位置(找到这个数字之前,遍历的数都是有序的)
}
if(i>=0){
int j = nums.length-1;
while(j>=0&&nums[j]<=nums[i]){
j--;//找到需要交换的数字
}
swap(nums,i,j);
}
reverse(nums,i+1);//交换后将之前遍历的有序数倒置(即变小,因为高位数已经变大了)
}
private void reverse(int[] nums,int start){
int i = start,j = nums.length-1;
while(i<j){
swap(nums,i,j);
i++;
j--;
}
}
private void swap(int[] nums,int i,int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
这一题也是类似的,只需要把输入的整数变成数组即可:
public int nextGreaterElement(int n) {
char[] a = ("" + n).toCharArray();
int i = a.length - 2;
while (i >= 0 && a[i + 1] <= a[i]) {
i--;
}
if (i < 0)
return -1;
int j = a.length - 1;
while (j >= 0 && a[j] <= a[i]) {
j--;
}
swap(a, i, j);
reverse(a, i + 1);
try {
return Integer.parseInt(new String(a));
} catch (Exception e) {
return -1;
}
}
private void reverse(char[] a, int start) {
int i = start, j = a.length - 1;
while (i < j) {
swap(a, i, j);
i++;
j--;
}
}
private void swap(char[] a, int i, int j) {
char temp = a[i];
a[i] = a[j];
a[j] = temp;
}