题目描述
实现获取下一个排列的函数,算法需要将给定的数字序列重新排列成字典序中下一个更大的排列,如果不存在则将数字重新排列成最小的排列(即升序排列),必须原地修改。
例如
1,2,3 --> 1,3,2
1,5,8,6,7,3,2,1 --> 1,5,8,7,1,2,3,6
为了得到下一个排列,首先找到从右往左的第一对nums[i-1] < nums[i]的一对数,然后在nums[i-1]的右边的序列中按照从右往左的顺序找到第一个大于nums[i-1]的元素nums[j],题目中要求的下一个更大的排列,所以将nums[i-1]与nums[j]交换,由于nums[i-1]是通过从右往左找到第一对nums[i-1] < nums[i]来确定的,所以在nums[i-1]的右边的序列是降序的。在交换了nums[i-1]和nums[i]后,还需要对nums[i-1]右边的序列进行翻转,使其变成升序子序列。代码如下:
/**
* 下一个排列
* 从右往左找到第一对nums[i]>nums[i-1],然后再从最右边往前找,找到第一个大于nums[i-1]的元素nums[j],交换nums[i-1]和nums[j],
* 最后再将nums[i-1]之后的元素反转。
* @param nums
*/
public void nextPermutation(int[] nums) {
int i = nums.length-1;
int flag = 0; //用于标记序列是否是全降序,0是,1不是
for(; i > 0; i--){
if(nums[i] > nums[i-1]){
i--;
flag = 1;
break;
}
}
if(flag == 1) {
int j = nums.length - 1;
for (; j >= 0; j--) {
if (nums[j] > nums[i]) {
int temp = nums[j];
nums[j] = nums[i];
nums[i] = temp;
break;
}
}
for (int k = i + 1, l = nums.length - 1; k < nums.length; k++, l--) {
if (k > (i + nums.length) / 2) {
break;
}
int temp = nums[k];
nums[k] = nums[l];
nums[l] = temp;
}
}
else{
for(int k = 0,l = nums.length-1; k < nums.length; k++, l--){
if(k > (nums.length-1)/2){
break;
}
int temp = nums[k];
nums[k] = nums[l];
nums[l] = temp;
}
}
}
时间复杂度为O(N)