下一个排列

105 阅读1分钟

这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战

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

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

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

示例 1:

输入:nums = [1,2,3]
输出:[1,3,2]

示例 2:

输入:nums = [3,2,1]
输出:[1,2,3]

示例 3:

输入:nums = [1,1,5]
输出:[1,5,1]

解题:

按题目的意思要获取下一个更大的排列,这个下一个一定得是接着的下一个,而不是比它大的中任意一个。 比如1,2,3,4,依次从小到大的排列为:

1,2,3,4
1,2,4,3
1,3,2,4
1,3,4,2
...
4,3,2,1

对于这些排列组合有 第一个列<第二个排列<第三个排列 这种顺序。

要获取这种排列,需要获取下一个比当前排列大的数,并且变大的幅度要最小,那么可以考虑从数组右边往左进行查找, 将左边的一个 [小数] 与右边的一个 [大数] 进行交换,此时得到的排列是变大了的。当然还要控制不能变得太大,所以 [大数] 要尽可能的小, 并且还要将交换后 [大数] 位置右边的元素从小到大排序,这样就可以保证这个排列比之前的大,变大的幅度又是最小的。

具体的例如[1,2,4,3],可以从数组右边往左进行查找,查找到nums[left]<nums[right],第一个左边元素小于右边元素的位置left下的元素, 这时left元素为2,这里的元素2就是 [小数] ;然后在从右往前找到nums[left]<nums[k],第一个大于left位置的元素,此时k下的元素为3,就是 [大数] ,然后就是交换 [小数][大数] 的位置变成:[1,3,4,2],最后再将 [大数] 右边的元素从小到大升序排列变为:[1,3,2,4],获得最终结果。 同样当第一次从右往左找不到符号条件的元素时,说明当前排列就是最大的排列,直接就可以将整个数组升序排列。

class Solution {

    public void nextPermutation(int[] nums) {
        int len = nums.length;
        int i = len - 2;
        while (i >= 0 && nums[i] >= nums[i + 1]) {
            i--;
        }
        if (i >= 0) {
            int k = len - 1;
            while (nums[i] >= nums[k]) {
                k--;
            }
            swap(nums, i, k);
        }
        reverse(nums, i + 1, len - 1);
    }

    public void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;

    }

    public void reverse(int[] nums, int i, int j) {
        while (i < j) {
            swap(nums, i++, j--);
        }
    }


}