题目描述:
实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列(即,组合出下一个更大的整数)。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须 原地 修改,只允许使用额外常数空间。
示例 1:
输入:nums = [1,2,3]
输出:[1,3,2]
示例 2:
输入:nums = [3,2,1]
输出:[1,2,3]
示例 3:
输入:nums = [1,1,5]
输出:[1,5,1]
示例 4:
输入:nums = [1]
输出:[1]
解题思路:
1,下一个数比当前的数大,因此只需要将后一位的大一些的数与前一位比较小的数,由于要排序,因此下一个数的增长幅度还尽量要小,这样才能满足,下一个排列与当前排列紧邻这个条件,为了达到这个要求,需要满足以下条件:
尽可能的地位进行交换,需要从后向前查找
将一个尽可能小的大一些的数与前面的小一些的数进行互换,比如123465,应该把5和4交换,而不是6和四交换。
将大数换到前面之后,将大数后面的数重置为升序,升序排列是最小的排列。也就是先找出一个最大的索引,再找出另一个最大的索引,将这两个索引所对应的值进行比较,如果第二个索引大于第一个索引,则互换位置。
时间复杂度:O(n)
空间复杂度:O(1)
代码实现:
public class Solution {
public void nextPermutation(int[] nums){
if (nums == null || nums.length ==0 ) return;
//从右至左找第一个相邻升序对
int firstIndex = -1;
for (int i = nums.length-2;i>=0;i--){
if (nums[i]<nums[i+1]){
firstIndex = i;
break;
}
}
//如果没有找到升序对,则数组是降序的,即本身是最大的,所以反转数组,使之成为最小的排列
if (firstIndex == -1){
reverse(nums,0,nums.length-1);
return;
}
//从右至左找第一个大于nums[firstIndex]的大数
int secondeIndex = -1;
for (int i = nums.length-1;i>=0;i--){
if (nums[i]>nums[firstIndex]){
secondeIndex = i;
break;
}
}
swap(nums,firstIndex,secondeIndex);
reverse(nums,firstIndex+1,nums.length-1);
return;
}
/**
* 定义一个将nums中[one,two]区间的元素原地倒排的函数
* @param nums
* @param one
* @param two
*/
public void reverse(int[] nums,int one,int two){
while (one < two){
swap(nums,one++,two--);
}
}
public void swap(int[] nums,int i,int n){
int temp = nums[i];
nums[i] = nums[n];
nums[n] = temp;
}
}