下一个排列[发挥主观能动性发现规律]

147 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第28天,下一个排列[发挥主观能动性发现规律] - 掘金 (juejin.cn)

前言

充分发挥主观能动性,找到题的个性所在,挖掘其特点,见招拆招,没有死板的套路,需要什么就用代码的分支/循环/递归/数据结构来完成即可。

一、下一个排列

image.png

二、逻辑分析与代码整理

package everyday.medium;

// 下一个排列
public class NextPermutation {
    /*
    target:把nums整体当作一个数,这些数字不变,取下一个要求比原数大的组合。
    core:什么时比原来大的组合?寻找问题个性所在,其实从后往前找到一个非递增的数,然后把后面刚好比它大的数和其交换,再翻转后面的数即可。

    注:如果遍历完都没找到,那就是特殊情况,直接翻转。
     */
    public void nextPermutation(int[] nums) {
        if (nums.length == 1) return;
        // 寻找非递增的那个数的idx,为了后面的交换。
        int i = nums.length - 2;
        while (i >= 0 && nums[i] >= nums[i + 1]) --i;

        int begin = 0;//翻转开始处,默认全部翻转。
        // 当i >= 0时,需要确定新的翻转开始处。
        if (i >= 0) {
            // 寻找需要交换的数字
            int idx = nums.length - 1;
            while (nums[idx] <= nums[i]) idx--;
            // 交换两者,且 i + 1 到 nums.length - 1保持单调递减,直接翻转。
            swap(nums, i, idx);
            // 确定从那里开始翻转
            begin = i + 1;
        }
        // 翻转
        reverse(nums, begin, nums.length);
    }

    public void reverse(int[] nums, int left, int right) {
        int mid = right - left >>> 1;
        for (int j = 0; j < mid; j++) {
            int t = nums[left + j];

            nums[left + j] = nums[right - 1 - j];
            nums[right - 1 - j] = t;
        }
    }

    // 交换两数。
    public void swap(int[] nums, int i, int j) {
        int t = nums[i];

        nums[i] = nums[j];
        nums[j] = t;
    }
}

总结

1)发挥主观能动性/思考力,发现问题个性,按逻辑写出代码,再整理逻辑代码。

参考文献

[1] LeetCode 下一个排列