【LeetCode】颜色分类

87 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第14天,点击查看活动详情

颜色分类

原题:leetcode-cn.com/problems/so…

描述

给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。

注意: 不能使用代码库中的排序函数来解决这道题。

进阶:

  • 一个直观的解决方案是使用计数排序的两趟扫描算法。

    首先,迭代计算出 0、1 和 2 元素的个数,然后按照 0、1、2 的排序,重写当前数组。

  • 你能想出一个仅使用常数空间的一趟扫描算法吗?

难度

中等

示例

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

思路

对数组进行遍历,使用两个指针分别用来交换 0 和 1。用指针 p0 来交换 0,p1 来交换 1,初始值都为 0。遍历数组时:

当元素值为 1 时,将 nums[i] 和 nums[p1] 交换,然后 p1++。

当元素值为 0 时,将 nums[i] 和 nums[p0] 交换,然后 p0++。p0++ 后,p0 指向的元素可能是 1,后续发生交换会把 1 交换出去,所以当 p0 < p1 时,将 nums[i] 和 nums[p1] 交换,最后无论是否有 p0 < p1,将 p0 和 p1 都后移一个位置。

代码

Rust

pub struct Solution {}
​
impl Solution {
    pub fn sort_colors(nums: &mut Vec<i32>) {
        // p0 表示 0 要放置的下标, p1 表示 1 要放置的下标
        let (mut p0, mut p1) = (0, 0);
        for i in 0..nums.len() {
            if nums[i] == 0 {
                // 交换 i 和 p0 指向的元素
                Solution::swap(nums, i, p0);
                // 有可能 p0 指向的元素为 1, 跟 i 发生了交换
                if p0 < p1 {
                    // 将 p1 和 i 交换
                    Solution::swap(nums, i, p1);
                }
                p0 += 1;
                p1 += 1;
            } else if nums[i] == 1 {
                // 交换 i 和 p1 指向的元素
                Solution::swap(nums, i, p1);
                p1 += 1;
            }
        }
    }
​
    fn swap(nums: &mut Vec<i32>, a: usize, b: usize) {
        let temp = nums[a];
        nums[a] = nums[b];
        nums[b] = temp;
    }
}
#[test]
fn test_sort_colors() {
    let mut nums = vec![2, 0, 2, 1, 1, 0];
    println!("{:?}", nums);
​
    Solution::sort_colors(&mut nums);
    println!("{:?}", nums);
}

运行结果:

[2, 0, 2, 1, 1, 0]
[0, 0, 1, 1, 2, 2]

Go

func sortColors(nums []int) {
    // p0 表示 0 要放置的下标, p1 表示 1 要放置的下标
    p0, p1 := 0, 0
    for i, num := range nums {
        if num == 0 {
            // 交换 i 和 p0 指向的元素
            nums[i], nums[p0] = nums[p0], nums[i]
            // 有可能 p0 指向的元素为 1, 跟 i 发生了交换
            if p0 < p1 {
                // 将 p1 和 i 交换
                nums[i], nums[p1] = nums[p1], nums[i]
            }
            p0++
            p1++
        } else if num == 1 {
            // 交换 i 和 p1 指向的元素
            nums[i], nums[p1] = nums[p1], nums[i]
            p1++
        }
    }
}
func TestSortColors(t *testing.T) {
    nums := []int{2, 0, 2, 1, 1, 0}
    t.Log(nums)
​
    sortColors(nums)
    t.Log(nums)
}

运行结果:

[2 0 2 1 1 0]
[0 0 1 1 2 2]

Java

public class Main {
​
    public static void sortColors(int[] nums) {
        // p0 表示 0 要放置的下标, p1 表示 1 要放置的下标
        int p0 = 0, p1 = 0;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == 0) {
                // 交换 i 和 p0 指向的元素
                swap(nums, i, p0);
                // 有可能 p0 指向的元素为 1, 跟 i 发生了交换
                if (p0 < p1) {
                    // 将 p1 和 i 交换
                    swap(nums, i, p1);
                }
                p0++;
                p1++;
            } else if (nums[i] == 1) {
                // 交换 i 和 p1 指向的元素
                swap(nums, i, p1);
                p1++;
            }
        }
    }
​
    public static void swap(int[] nums, int a, int b) {
        int temp = nums[a];
        nums[a] = nums[b];
        nums[b] = temp;
    }
​
    public static void main(String[] args) {
        int[] nums = new int[]{2, 0, 2, 1, 1, 0};
        System.out.println(Arrays.toString(nums));
​
        sortColors(nums);
        System.out.println(Arrays.toString(nums));
    }
}

运行结果:

[2, 0, 2, 1, 1, 0]
[0, 0, 1, 1, 2, 2]