642 字
3 分钟
颜色分类

题目描述#

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

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

必须在不使用库内置的 sort 函数的情况下解决这个问题。

解题思路#

  1. 三指针分区
    • 使用 low 指针标记0的右边界
    • 使用 high 指针标记2的左边界
    • 使用 mid 指针遍历数组
  2. 元素分类
    • 遇到0:与low交换,lowmid右移
    • 遇到1:mid右移
    • 遇到2:与high交换,high左移
  3. 单向遍历
    • 只需一次遍历完成排序
  4. 原地操作
    • 无需额外存储空间
  5. 终止条件
    • 当 mid > high 时完成

关键洞察#

  1. 分区思想
    • 将数组划分为0区、1区和2区
  2. 边界移动
    • low 保证左侧全为0
    • high 保证右侧全为2
  3. 交换逻辑
    • 遇到2时 mid 不移动(交换后需重新判断)
  4. 遍历效率
    • 每个元素最多被访问两次
  5. 荷兰国旗
    • 基于Dijkstra的三色问题解决方案

复杂度分析#

指标说明
时间复杂度O(n):单次遍历数组
空间复杂度O(1):原地操作,仅需常数空间
最优情况O(n):全0数组仍需完整遍历
最坏情况O(n):同上

代码实现#

/**
* @param {number[]} nums
* @return {void} Do not return anything, modify nums in-place instead.
*/
var sortColors = function (nums) {
let red = 0, white = 0;
for (const num of nums) {
if (num === 0) red++;
if (num === 1) white++;
}
let i = 0;
while (red) {
nums[i++] = 0;
red--;
}
while (white) {
nums[i++] = 1;
white--;
}
while (i < nums.length) {
nums[i++] = 2;
}
};
pub fn sort_colors(nums: &mut Vec<i32>) {
let (mut low, mut mid, mut high) = (0, 0, nums.len() - 1);
while mid <= high {
match nums[mid] {
0 => {
nums.swap(low, mid);
low += 1;
mid += 1;
}
1 => {
mid += 1;
}
2 => {
nums.swap(mid, high);
if high == 0 { break; } // 防止无符号整数下溢
high -= 1;
}
_ => unreachable!(),
}
}
}
def sortColors(nums):
low, mid, high = 0, 0, len(nums) - 1
while mid <= high:
if nums[mid] == 0:
nums[low], nums[mid] = nums[mid], nums[low]
low += 1
mid += 1
elif nums[mid] == 1:
mid += 1
else: # nums[mid] == 2
nums[mid], nums[high] = nums[high], nums[mid]
high -= 1

实际应用场景#

  1. 图像处理:RGB像素值快速排序`
  2. 数据统计:多类别数据频次统计前处理`
  3. 硬件设计:信号灯状态机控制`
  4. 基因排序:DNA碱基序列分类`

相似题目#

颜色分类
https://website-truelovings-projects.vercel.app/posts/algorithms/颜色分类/
作者
欢迎来到StarSky的网站!
发布于
2025-09-02
许可协议
CC BY-NC-SA 4.0