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

题目描述:

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

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

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

以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
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)

原文地址:https://www.cnblogs.com/ysw-go/p/11771966.html