题目
实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须原地修改,只允许使用额外常数空间。
以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/next-permutation
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
将题目翻译一下:在输入给出的数字所能组成的所有排列中,找出一个刚好比输入大的数。参考LeetCode上的热评,将算法过程总结如下:
- 从后向前,找出第一个相邻正序对;
- 若不存在相邻正序对,则翻转数组;
- 若存在相邻正序对,即存在 index >= 0, 使得 nums[index] < nums[index + 1],则翻转nums[index + 1] 至 nums[len - 1];
- 找出 nums[index] 后,刚好比 nums[index] 大的数 nums[index2],对调两者位置。
代码如下:
public void nextPermutation(int[] nums){
// 特殊值判断
int len = nums.length;
if(len <= 1){
return;
}
// 从后向前找到第一个正序对
int index = len - 2;
while(index >= 0 && nums[index] >= nums[index + 1]){
index--;
}
// 不存在正序对的情况,即数组为完全倒序,下一个排列应为升序排列
if(index == -1){
reverse(nums, 0, len - 1);
return;
}
// 翻转 index 后的数组
reverse(nums, index + 1, len - 1);
// 找到 index 后第一个比 nums[index] 大的数
int index2 = index + 1;
while(index2 < len && nums[index2] <= nums[index]){
index2++;
}
// 交换位置
swap(nums, index, index2);
}
/**
* 翻转数组 nums 中 nums[begin] 至 nums[end] 的部分
* @param nums
* @param begin
* @param end 左闭右闭区间
*/
private void reverse(int[] nums, int begin, int end){
int len = end - begin + 1;
for(int i = 0; i < len / 2; i++){
int temp = nums[begin + i];
nums[begin + i] = nums[end - i];
nums[end - i] = temp;
}
}
/**
* 交换 nums[index1] 和 nums[index2] 的位置
* @param nums
* @param index1
* @param index2
*/
private void swap(int[] nums, int index1, int index2){
int temp = nums[index1];
nums[index1] = nums[index2];
nums[index2] = temp;
}
参考:LeetCode热门题解评论