实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须原地修改,只允许使用额外常数空间。
以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1
思路与代码
- 1 从右往左遍历,找到第一个破坏降序的数字5。
- 2 从5往右遍历,找到比5大中最小的数字6,交换5和6的位置。
- 3 对交换后6右边的序列逆序即可。(若第一步中发现整个nums就是降序,那么直接将nums逆序即可)
时间复杂度 : O(n)
1 2 3 步骤的时间复杂度都是O(n)
所以总体是O(n)
空间复杂度 : O(1)
class Solution {
public void nextPermutation(int[] nums) {
int swapIndex = findFirstSmallNum(nums);
if (swapIndex >= 0){
for (int i = nums.length - 1; i > swapIndex; i--){
if (nums[i] > nums[swapIndex]){
swap(nums, i, swapIndex);
break;
}
}
}
reverse(nums, swapIndex+1, nums.length - 1);
}
// 从右往左找到第一个破坏降序的数字
public int findFirstSmallNum (int[] nums) {
int i = nums.length - 1;
while (i > 0){
if (nums[i - 1] < nums[i])
return i-1;
i--;
}
return -1;
}
public void reverse(int[] nums, int left, int right) {
while (left < right)
swap(nums, left++, right--);
}
public void swap(int[] nums, int a, int b){
int tmp = nums[a];
nums[a] = nums[b];
nums[b] = tmp;
}
}