Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers.
If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).
The replacement must be in-place and use only constant extra memory.
Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1
给出一个数组,给出下一个排列,也就是找出当前数组的数字排列成的下一个更大的数字
不可以用新的数组,要在原数组中直接交换数字
如果数组是降序,也就是已经是可以排列的最大数字,那么就升序排列,也就是循环的找出最小数字
思路:
从数组的最后一个数字开始向前,找出升序的位置
如[1, 3, 2] , [3,2]的部分是降序的,1到3是升序的,升序的位置在index = 0
找出index=0之后的部分,也就是[3,2]中仅仅大于nums[index]值的,交换
nums[index] = 1, 仅仅大于1的是2,交换1,2,得到[2, 3, 1]
还是index = 0之后的部分,上一步交换之后仍然是降序的,现在按升序排列,得到[2, 1, 3]
即是结果
原理:
降序排列的部分显然已经是最大值了,也就是说index=0之后的部分已经是最大
所以找到下一个排列的方法就是在降序的部分中找到仅仅大于nums[index]的数字,
这样与nums[index]交换以后整体nums就会变大
但是这时不是下一步的排列,把index之后的部分升序才能做到index后的部分是最小数字,实现下一排列的目标
public void nextPermutation(int[] nums) {
if(nums == null || nums.length == 0) {
return;
}
int n = nums.length;
int index = n;
int left = 0;
int right = n - 1;
//从后往前找到第一个升序的位置
for(int i = n - 1; i >= 1; i--) {
if(nums[i - 1] < nums[i]) {
index = i - 1;
break;
}
}
//调换nums[index]与它后面部分中仅仅大于nums[index]值的
for(int i = n - 1; i > index; i--) {
if(nums[i] > nums[index]) {
//交换元素
int tmp = nums[index];
nums[index] = nums[i];
nums[i] = tmp;
break;
}
}
//index后面的部分现在是降序的,把它升序排列
//如果整体是降序的,就整体升序排列
if(index == n) {
left = 0;
} else {
left = index + 1;
}
//升序排列
while(left < right) {
int tmp = nums[left];
nums[left] = nums[right];
nums[right] = tmp;
left ++;
right --;
}
}
也可以先升序排列后面降序的部分,再把降序的前一个元素和后面仅比它大的元素交换。
当整体降序时,可以看到排序后不需要再找交换的元素。
public void nextPermutation(int[] nums) {
int n = nums.length;
if(n == 1) return;
int start = n - 1;
int left = 0;
int right = n - 1;
while(start >= 1) {
if(nums[start - 1] >= nums[start]) start --;
else break;
}
//Arrays.sort(nums, start, n);
left = start;
right = n - 1;
while(left < right) {
int tmp = nums[right];
nums[right] = nums[left];
nums[left] = tmp;
left ++;
right --;
}
if(start == 0) return;
for(int i = start; i < n; i++) {
if(nums[i] > nums[start - 1]) {
int tmp = nums[i];
nums[i] = nums[start - 1];
nums[start - 1] = tmp;
break;
}
}