【No.5】【LeetCode系列】【数组】75. 颜色分类(中等难度)|刷题打卡

203 阅读2分钟

1. 题目描述

题目地址

题目描述

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

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

进阶要求

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

示例

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

2. 解题思路

方法一:计数排序法(简单但不符合题意要求)

思路

  • 主旨:使用三个变量,遍历一遍数组,记录每种颜色出现的数量。然后再遍历一遍数组,根据数量分别将数组置为相应颜色的值。
  • 操作流程:
    1. 定义三个变量red,white,分别记录红色、白色出现的数量(蓝色无需记录,除了红色和白色之外,都是蓝色)。
    2. 遍历数组,如果值为0red的值加一;如果值为1white的值加一。
    3. 再次遍历数组,为数组的0red位置的元素,赋值为0;为数组的redred+white位置的元素,赋值为1;为数组的red+white至末尾nums.length-1位置的元素,赋值为2

代码实现

 public void sortColors(int[] nums) {
        if (nums.length < 2) {
            return;
        }

		// 首次遍历数组,分别记录红色、白色出现的次数
        int red = 0, white = 0;
        for(int i = 0; i < nums.length; i++) {
            if (nums[i] == 0) {
                red++;
            } else if (nums[i] == 1) {
                white++;
            }
        }

		// 再次遍历数组,为相应的颜色赋值
        int index = 0;
        while (index < red) {
            nums[index++] = 0;
        }
        while (index < (red + white)) {
            nums[index++] = 1;
        }
        while (index < (nums.length)) {
            nums[index++] = 2;
        }
    }

复杂度分析

  • 时间复杂度:O(n)。总共有n个元素,第一次遍历计数需要n步,第二次遍历赋值需要n步,总共2n次操作。
  • 空间复杂度:O(1)。只需要常数的空间存放若干变量。 执行结果

方法二:双指针法(荷兰国旗问题,推荐)

背景

这是一道经典的荷兰国旗问题,是荷兰计算机科学家Dijkstra提出的。我们在大学《数据结构与算法》这门课程里,学过一个叫做Dijkstra最短路径算法的算法,就是这个科学家提出的。《高频面试考题:荷兰旗问题》这篇文章详细介绍了荷兰国旗问题,感兴趣的可以参考下。本文就不做展开了。

思路

  • 主旨:在数组中定义左中右三块区域,分别赋值0,1,2,构成红、白、蓝三块区域。然后遍历整个数组,比较当前元素是否为0,1或者2。再分别与红区的右端或是蓝区的左端元素交换。
  • 操作流程:
    1. 定义p0、i、p2三个指针,划定红白蓝三块区域。初始值p0、i指向数组最左端,p2指向数组最右端。 这三快区域分别为:
      • 红区:[p0, i]。(左右闭合)
      • 白区:(i, p2)(左右打开)
      • 蓝区:[p2, nums.length](左右闭合)
    2. 遍历数组,直到i>p2。
      • 若i指向元素值为0(该值应放置于红区[p0, i]),则交换i与p0,并使p0和i向右移动一格。
      • 若i指向的元素为1(该值应放置于红区(i, p2)),则不做交换,只使i向右移动一个。
      • 若i指向的元素为2(该值应放置于蓝区[p2, nums.length]),则交换i与p2,但只使p2向左移动一格。之所以不使i加一,是因为从p2交换到i的元素,有可能也是值为2的。如果跳过此值,则(i,p2)中就出现了值为2的元素,也就是白区出现了蓝色,是不符合定义的。

代码实现

public void sortColors(int[] nums) {
       int p0 = 0, i = 0, p2 = nums.length -1;
        while (i <= p2) {
            if (nums[i] == 0) {
                swap(nums, i, p0);
                p0++;
                i++;
            } else if (nums[i] == 2) {
                swap(nums, i, p2);
                p2--;
            } else {
                i++;
            }
        }
    }

    public static void swap(int[] nums, int a, int b) {
        int temp = nums[a];
        nums[a] = nums[b];
        nums[b] = temp;
    }

复杂度分析

  • 时间复杂度:O(n)。总共有n个元素,只需遍历一遍,所以会遍历n个元素。
  • 空间复杂度:O(1)。只需要常数的空间存放若干变量。 执行结果

本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情