在算法面试中,有一种经典问题被称为"荷兰国旗问题"(Dutch National Flag Problem),它不仅是LeetCode第75题(颜色分类),更是理解双指针技巧的绝佳案例。今天我们就来一起探讨这个问题,领略左程云老师传授的精妙解题思路!
题目描述:颜色分类(Sort Colors)
题目要求:给定包含红色、白色、蓝色共 n 个元素的数组,原地排序使得相同颜色的元素相邻,并按照红、白、蓝顺序排列。
要求使用一趟扫描且常数空间完成。
示例:
输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]
难度:★★★☆☆(中等) 大厂出现频率:字节跳动(高频)、百度(高频)、美团(高频)
左程云解法精讲
左程云在算法课程中强调,这道题的核心在于三指针分区技巧:
算法思路解析
graph TD
A[初始化三个指针] --> B[左边界 p0=0]
A --> C[当前指针 curr=0]
A --> D[右边界 p2=n-1]
B --> E{{curr <= p2?}}
E -- 是 --> F{当前值 nums[curr]}
F -- 0 --> G[交换 curr 和 p0
p0++
curr++]
F -- 1 --> H[curr++]
F -- 2 --> I[交换 curr 和 p2
p2--]
G --> E
H --> E
I --> E
E -- 否 --> J[完成排序]
Java实现代码:
public void sortColors(int[] nums) {
// 左程云三指针分区技巧
int p0 = 0; // 0的右边界
int curr = 0; // 当前指针
int p2 = nums.length - 1; // 2的左边界
while (curr <= p2) {
if (nums[curr] == 0) {
// 交换当前元素和p0位置
swap(nums, curr, p0);
p0++;
curr++;
} else if (nums[curr] == 2) {
// 交换当前元素和p2位置
swap(nums, curr, p2);
p2--;
} else {
// 遇到1直接前进
curr++;
}
}
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
关键技巧解析
三指针分区原理(左程云版本)
- p0指针:指向0序列的右边界
- p2指针:指向2序列的左边界
- curr指针:扫描未知区域
操作规则:
- 遇到0:交换给p0位置,并同时移动curr和p0
- 遇到1:保留原位置,仅curr移动
- 遇到2:交换给p2位置,仅p2移动(curr不移动)
为什么curr在遇到2时不移动?
因为从p2位置交换过来的元素值可能是0或1,需要再次处理!
时间复杂度分析
- 时间复杂度:O(n) - 仅遍历一次数组
- 空间复杂度:O(1) - 常量级额外空间
实际应用场景
- 操作系统内存管理:分页式内存管理中不同状态页面的分组
- 图像处理:像素分类和压缩
- 数据分析:大规模数据集的快速三值分类
- 排序算法优化:快速排序的3-way partition优化
- 广告系统:用户行为数据的分级处理
左程云解题方法论
通过这道题,我们可以学习到左程云传授的解题心法:
- 分而治之:将问题分解为多个分区处理
- 指针协作:多指针协同完成数组操作
- 原地操作:常数空间复杂度解决方案
- 边界控制:精确控制指针移动条件
"荷兰国旗问题教会我们:复杂排序可以通过简单分区技巧优雅解决" —— 左程云
学习资源推荐
左程云老师精心整理的**《算法面试突击笔记》** 包含:
- 100+高频面试题精解
- 双指针技巧详解
- 分区算法应用场景分析
- 系统设计面试要点
si我"666"即可获取完整电子版!
变种与扩展
- 四色分类问题(LeetCode会员题)
- 快速排序3-way partition优化
- 奇数偶数分组(LeetCode 905题)
- 按符号分区(LeetCode 922题)
总结
荷兰国旗问题看似简单,却是训练算法思维的最佳题材:
- 理解多指针协作的精髓
- 掌握原地操作的技巧
- 学会分区算法的实现
掌握此类问题将使你在算法面试中占据优势!
本文分享的解题思路选自左程云老师算法课程核心内容。如需系统学习完整算法体系,si我"666"获取《算法面试突击笔记》,助力你的面试备战!