Leetcode题目31.下一个排列(中等)

时间:2022-12-15 11:26:26

题目描述:

实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。

如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。

必须原地修改,只允许使用额外常数空间。

以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1

题目解析

先找出最大的索引 k 满足 nums[k] < nums[k+1],如果不存在,就翻转整个数组;
再找出另一个最大索引 l 满足 nums[l] > nums[k];
交换 nums[l] 和 nums[k];
最后翻转 nums[k+1:]。

比如 nums = [1,2,7,4,3,1],下一个排列是什么?

我们找到第一个最大索引是 nums[1] = 2

再找到第二个最大索引是 nums[4] = 3

交换,nums = [1,3,7,4,2,1];

翻转,nums = [1,3,1,2,4,7]

代码实现:

class Solution {

      public static void nextPermutation(int[] nums) {

        //寻找满足nums[i]<nums[i+1]的最大索引
int firstIndex = -1;
for (int i = 0; i < nums.length - 1; i++) {
if (nums[i] < nums[i + 1]) {
firstIndex = i;
}
}
//没有找到这样的firstIndex,则翻转整个数组,变成最小的字典序排列
if (firstIndex == -1) {
//sort函数将nums进行升序排列,即翻转了整个数组
Arrays.sort(nums);
} else {
//寻找满足nums[l]>nums[k]的最大索引
int secondIndex = firstIndex + 1;
for (int j = firstIndex + 1; j < nums.length; j++) {
if (nums[j] > nums[firstIndex]) {
secondIndex = j;
}
}
//交换两个位置的元素
swap(nums, firstIndex, secondIndex);
//翻转从k+1到n的所有元素的位置
reverse(nums, firstIndex + 1, nums.length - 1); } } private static void reverse(int[] nums, int begin, int length) { for (int i = begin, j = length; i <= begin + (length - begin) / 2; i++, j--) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
} private static void swap(int[] nums, int firstIndex, int secondIndex) { int temp = nums[firstIndex];
nums[firstIndex] = nums[secondIndex];
nums[secondIndex] = temp;
}
}

时间复杂度:O(n)

空间复杂度:O(1)