算法题解
LeetCode Hot 100 | 98. 颜色分类
两次扫描分别归位 0 和 1 实现原地排序,进阶可用荷兰国旗三指针算法一次遍历完成。
LeetCodeHot100技巧C++面试算法
LeetCode 75. 颜色分类 (Sort Colors)
1. 核心思路:两次扫描 + 双指针
本题要求对包含 0、1、2 的数组进行原地排序,等价于 荷兰国旗问题 的简化版本。
核心思想: 使用一个指针 current_index 维护「已排序部分的末尾位置」。
算法流程(两次扫描):
第一轮扫描 —— 把 0 放到前面:
- 遍历数组,遇到值为 0 的元素,将其与
current_index位置交换 current_index++,指向下一个 0 应该存放的位置- 结束后,所有 0 都在数组前部,
current_index指向第一个 1 应该放的位置
第二轮扫描 —— 把 1 放到 0 后面:
- 从数组开头重新遍历,遇到值为 1 的元素,将其与
current_index位置交换 current_index++,继续向后扩展已排序区域- 剩余的元素自然就是 2,无需处理
2. 代码实现
class Solution {
public:
void sortColors(vector<int>& nums) {
int current_index = 0;
// 第一遍扫描:把所有 0 放到数组前面
for (int i = 0; i < nums.size(); i++) {
if (nums[i] == 0) {
swap(nums[i], nums[current_index]);
current_index++;
}
}
// 第二遍扫描:从 current_index 开始,把所有 1 放到 0 后面
for (int i = 0; i < nums.size(); i++) {
if (nums[i] == 1) {
swap(nums[i], nums[current_index]);
current_index++;
}
}
// 此时,2 已经自动排在最后,无需额外处理
}
};
3. 关键细节备忘 (Key Takeaways)
-
current_index 的作用:
- 第一轮结束后,
[0, current_index-1]区域全是 0 - 第二轮结束后,
[0, current_index-1]区域包含所有的 0 和 1,且有序 - 剩余的
[current_index, end]自然全是 2
- 第一轮结束后,
-
最优解 —— 三指针一次扫描(荷兰国旗算法):
- 使用三个指针:
left(0的右边界)、right(2的左边界)、i(当前扫描位置) - 一次遍历完成分类,遇到 0 放左边,遇到 2 放右边,遇到 1 跳过
- 时间复杂度: — 只需遍历一次
- 空间复杂度: — 原地排序
- 使用三个指针:
-
两次扫描 vs 一次扫描:
- 两次扫描代码更易理解,但常数较大(遍历两次)
- 荷兰国旗算法更高效,但指针逻辑稍复杂
-
复杂度分析(当前解法):
- 时间复杂度: — 虽然遍历两次,但仍是线性时间
- 空间复杂度: — 原地排序,只使用常数额外空间