[前端]_一起刷leetcode 75. 颜色分类

126 阅读3分钟

大家好,我是挨打的阿木木,爱好算法的前端摸鱼老。最近会频繁给大家分享我刷算法题过程中的思路和心得。如果你也是想提高逼格的摸鱼老,欢迎关注我,一起学习。

题目

75. 颜色分类

给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地**对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。

 

示例 1:

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

示例 2:

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

示例 3:

输入: nums = [0]
输出: [0]

示例 4:

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

 

提示:

  • n == nums.length
  • 1 <= n <= 300
  • nums[i] 为 01 或 2

 

进阶:

  • 你可以不使用代码库中的排序函数来解决这道题吗?
  • 你能想出一个仅使用常数空间的一趟扫描算法吗?

思路

  1. 先通过一轮遍历,记录0所在的后一个位置索引,每次遇到0, 就交换节点的位置,然后把索引值+1,这样子一轮遍历过后所有的0就能被全部交换到前面去;
  2. 再通过一轮遍历,记录2所在的前一个位置索引,每次遇到2, 就交换节点的位置,然后把索引值-1,这样子一轮遍历过后所有的2就能被全部交换到后面了。

实现

/**
 * @param {number[]} nums
 * @return {void} Do not return anything, modify nums in-place instead.
 */
var sortColors = function(nums) {
    const n = nums.length;
    let left = 0, right = n - 1;

    // 从左到右交换节点, 把0换到最前面
    for (let i = 0; i < n; i++) {
        if (nums[i] === 0) {
            if (i !== left) {
                [ nums[i], nums[left] ] = [ nums[left], nums[i] ];
            }
            left++;
        }
    }

    // 从右到左交换节点, 把2换到最后面
    for (let i = n - 1; i >= 0; i--) {
        if (nums[i] === 2) {
            if (i !== right) {
                [ nums[i], nums[right] ] = [ nums[right], nums[i] ];
            }
            right--;
        }
    }

    return nums;
};

优化

翻车

我们可以把上述过程合并成同一步。常规做法我们可能会统计前面0的数量,如果找到2的时候,我们会从后面开始找到第一个不为2的元素换过去,这样子如果后面是0换回来可能会出问题,这里我先上演一波翻车事例, 这逻辑乍一看没什么毛病,实际上当最后一个元素是0的时候,会错误的把0带回来后就跳过了。

/**
 * @param {number[]} nums
 * @return {void} Do not return anything, modify nums in-place instead.
 */
var sortColors = function(nums) {
    const n = nums.length;
    let left = 0, right = n - 1;

    // 从左到右交换节点, 把0换到最前面
    for (let i = 0; i <= right; i++) {
        if (nums[i] === 0) {
            [ nums[i], nums[left] ] = [ nums[left], nums[i] ];
            left++;
        } else if (nums[i] === 2) {
            // 万一人家原本就是2
            while (nums[right] === 2) {
                right--;
            }

            // 判断是否需要交换
            if (right > i) {
                [ nums[i], nums[right] ] = [ nums[right], nums[i] ];
                right--;
            }
        }
    }

    return nums;
};

最终代码

/**
 * @param {number[]} nums
 * @return {void} Do not return anything, modify nums in-place instead.
 */
var sortColors = function(nums) {
    const n = nums.length;
    let left = 0, right = n - 1;

    // 从左到右交换节点, 把0换到最前面
    for (let i = 0; i <= right; i++) {
        if (nums[i] === 2) {
            // 万一人家原本就是2
            while (nums[right] === 2) {
                right--;
            }

            // 判断是否需要交换
            if (right > i) {
                [ nums[i], nums[right] ] = [ nums[right], nums[i] ];   
                right--;
            }
        }

        if (nums[i] === 0) {
            [ nums[i], nums[left] ] = [ nums[left], nums[i] ];
            left++;
        }
    }

    return nums;
};

看懂了的小伙伴可以点个关注、咱们下道题目见。如无意外以后文章都会以这种形式,有好的建议欢迎评论区留言。