642 字
3 分钟
颜色分类

题目描述
给定一个包含红色、白色和蓝色、共 n
个元素的数组 nums
,原地 对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
我们使用整数 0
、 1
和 2
分别表示红色、白色和蓝色。
必须在不使用库内置的 sort 函数的情况下解决这个问题。
解题思路
- 三指针分区:
- 使用
low
指针标记0的右边界 - 使用
high
指针标记2的左边界 - 使用
mid
指针遍历数组
- 使用
- 元素分类:
- 遇到0:与
low
交换,low
和mid
右移 - 遇到1:
mid
右移 - 遇到2:与
high
交换,high
左移
- 遇到0:与
- 单向遍历:
- 只需一次遍历完成排序
- 原地操作:
- 无需额外存储空间
- 终止条件:
- 当
mid > high
时完成
- 当
关键洞察
- 分区思想:
- 将数组划分为0区、1区和2区
- 边界移动:
low
保证左侧全为0high
保证右侧全为2
- 交换逻辑:
- 遇到2时
mid
不移动(交换后需重新判断)
- 遇到2时
- 遍历效率:
- 每个元素最多被访问两次
- 荷兰国旗:
- 基于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
实际应用场景
- 图像处理:RGB像素值快速排序`
- 数据统计:多类别数据频次统计前处理`
- 硬件设计:信号灯状态机控制`
- 基因排序:DNA碱基序列分类`