参考官方题解:
之前按照一个C++大佬解法改写Java直接超时了,还是要少定义不必要的变量。
“下一个排列”:主要就是要找到当前数字组合的下一个更大的一个数字组合,比如123,对于三个值【1,2,3】下一个更大的数排列起来就是【1,3,2】也就是‘132’
主要思路就是:
- 先从后往前找到第一个相邻的两个数字,满足前小后大的要求,比如1234653,很明显刚开始的(5,3)(6,5)不满足要求,指针往前移,找到第一个前小后大的数字对(4,6) 。
- 对于4之后的数字【653】我们要从后往前找到第一个比4大的数字,这样保证是下一个最大的数字,数字3不行pass,找到5比4大,交换4和5,最后四位数得到【5643】。
- 这时候其实还是不能保证是下一个最大,因为【4653】下一个最大肯定要是首个数字变大,后面小的情况,也就是【5346】,很明显,对于我们上一步得到的【5643】这里要对后面的数字【643】进行排序,让那个后面的数字升序排序【346】,这样就满足了下一个最大的排序啦。(可以发现后面的数字是一个逆序排的,所以我们只需要倒置数字就好了)
- 当然要注意的是,如果找不到前小后大的情况,直接就不满足了,排序就好了。
代码如下:
class Solution {
public void nextPermutation(int[] nums) {
// i: 从倒数第二个节点开始
// 找到第一个相邻的对,满足nums[i]<nums[i+1]
int i = nums.length-2;
while(i>=0 && nums[i]>=nums[i+1]){
i--;
}
// 需要判断是不是已经遍历完了(此时i<0)都没有找到这样的相邻对【小,大】
// such as: 3,2,1 → 1,2,3
// k: 初始为数组最后一个值 从[i+1,k]找到一个比较小的数k,使(i,k)对满足nums[i]<nums[k]
int k = nums.length-1;
if(i>=0){
while(k>=i+1 && nums[i]>=nums[k]){
k--;
}
// 找到k之后,交换i和k
swap(nums,i,k);
}
// 对i之后的数组进行从小到大升序排列,因为后面是逆序,所以只需要转置即可
reverse(nums,i+1);
}
public void swap(int[] nums,int i,int j){
int temp = nums[i];
nums[i]=nums[j];
nums[j]=temp;
}
public void reverse(int[] nums, int s){
int left = s;
int right = nums.length-1;
while(left<right){
swap(nums,left,right);
left++;
right--;
}
}
}