0
点赞
收藏
分享

微信扫一扫

LeetCode31. 下一个排列(Java版)

千行 2022-01-11 阅读 51
java算法

31. 下一个排列(中等)

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

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

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

示例 1:

示例 2:

示例 3:

示例 4:

提示:

  • 1 <= nums.length <= 100
  • 0 <= nums[i] <= 100

思路

最重要的是弄清楚什么是下一个排列?这个排列“递增”的规律是什么?

排列组合的顺序是自小到达逐渐演变的;例如:对于5个数字的排列12354和12345,排列12345在前,排列12354在后。按照这样的规定,5个数字的所有的排列中最前面的是12345,最后面的是54321。

全排列的算法如下:

1)从排列的最右端开始,找出第一个比右边数字小的数字(即 a[i] < a[i+1])的序号i(i为数组下标);
2)在a[i]的右边的所有数字中(即[i + 1, n]中),从右到左找出第一个比a[i]大的数的序号j;(因为右边的数从右至左是递增的) ;
3)对换a[i]和a[j]
4)再将a[j + 1] … a[n]反转,这就是下一个排列

这题更像是一个数学题,知道排列的规律很好处理,但是…

代码

class Solution {
    public void nextPermutation(int[] nums) {
        int n = nums.length;
        int left = n - 2;
        // 从后往前找到第一个nums[i] > nums[i-1]的值,将(i-1)赋值给left
        while (left >= 0 && nums[left] >= nums[left + 1]) {
            left --;
        }
        // 可能当前排列是最大的,所以要判断left >= 0
        if (left >= 0) {
            int j = nums.length - 1;
            // 从[left + 1, n]中找到靠右侧第一个大于nums[left]的值
            while (j >= 0 && nums[left] >= nums[j]) {
                j--;
            }
            swap(nums, left, j);
        }
        //将[left + 1, n]位置的数据正序排序(反转后的即为正序排序)
        reverse(nums, left + 1, n - 1);
    }

    private void swap(int[] nums, int left, int right) {
        int temp = nums[left];
        nums[left] = nums[right];
        nums[right] = temp;
    }

    private void reverse(int[] nums, int left, int right) {
        while (left < right) {
            swap(nums, left, right);
            left++;
            right--;
        }
    }
}

复杂度分析

  • 时间复杂度:O(N),其中N 为数组长度。我们至多只需要扫描两次序列、进行一次反转操作。

  • 空间复杂度:O(1),存放诸如n、left等变量

举报

相关推荐

0 条评论