描述
给定一个整数数组来表示排列,找出其之后的一个排列。
排列中可能包含重复的整数
样例
给出排列[1,3,2,3]
,其下一个排列是[1,3,3,2]
给出排列[4,3,2,1]
,其下一个排列是[1,2,3,4]
思路:
1. 先找到需要改变的高位:从右向左扫描排列,若一直满足nums[i] > nums[i - 1],则说明这些元素是满足高位大于低位的,不需操作,直到找到nums[i] < nums[i - 1],找到高位比低位小的了,而且是“最低”的高位,这个位置就是我们需要做交换操作的。比如:6, 8, 7, 4, 3, 2 当中的8(发现6 < 8)
2. 第二步找要和这个高位交换的低位:原则是尽量寻找只比这个高位“大一点”的低位,因为只是下一个排列。因为在这个高位右边的数组满足从右往左递增,所以,我们重新从右边起扫描,找到第一个比这个高位大的元素。比如:6, 8, 7, 4, 3, 2 中的7.
3. 交换高位与低位,使得高位变大:比如6, 8, 7, 4, 3, 2 -> 7, 8, 6, 4, 3, 2
4. 此时,不论交换后的高位后面的元素是如何排列的,都肯定比之前的排列靠后了。因为只是下一个排列,所以我们现在尽量要现在的这个排列“靠前”,怎么做呢,就是按升序排列高位后面的元素,比如:按升序排列此时7后面的元素。因为此时高位后面的元素一定是从左往右,从大到小,所以,也相当于是翻转这一部分的数组。比如:7, 8, 6, 4, 3, 2 -> 7, 2, 3, 4, 6, 8
Java代码:
public static int[] nextPermutation(int[] nums) {
// write your code here
if(nums==null || nums.length==0 || nums.length==1){
return nums;
}
// 从右边开始找前一位比当前位小的数
int len = nums.length;
int i = len-1;
for (;i>0;i--){
if(i>0 && nums[i]>nums[i-1]){
break;
}
}
// 因为需要找下一个大的数,所以从右向左,找到第一个刚刚比 i-1 位置大的那个数
if(i>0){
int j = len-1;
for (; j > i-1; j--) {
if(nums[j]>nums[i-1]){
break;
}
}
// 交换 i-1 j
int temp = nums[i-1];
nums[i-1] = nums[j];
nums[j] = temp;
}
// 逆转 i-1 后面的数组
int pre = i, last = len-1;
while (pre<last){
int temp = nums[pre];
nums[pre] = nums[last];
nums[last] = temp;
pre++;
last--;
}
return nums;
}
参考:
https://blog.csdn.net/guoziqing506/article/details/51787763