1. 问题背景与需求分析
这道题目来自力扣(LeetCode)的热门100题系列,编号75,题目名为"颜色分类"。题目要求将一个包含红色、白色和蓝色元素的数组,按照红、白、蓝的顺序进行原地排序。其中红色用0表示,白色用1表示,蓝色用2表示。
在实际编程面试中,这类数组操作问题非常常见。它不仅考察基础编程能力,更检验开发者对算法效率的理解和优化能力。题目特别强调"原地排序"的要求,这意味着我们不能使用额外的存储空间,必须在原数组上直接操作。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 算法思路解析
2.1 直观解法与局限性
最直观的解法可能是直接调用语言内置的排序函数,比如在Python中使用nums.sort()。这种方法虽然简单,但完全忽略了题目考察的重点,也无法展示我们的算法能力。它的时间复杂度是O(nlogn),空间复杂度是O(1)(取决于具体实现)。
另一个思路是计数排序:先遍历一次数组统计0、1、2的个数,然后第二次遍历重新填充数组。这种方法时间复杂度是O(n),但需要两次遍历,且严格来说不算"原地"排序,因为使用了额外的计数空间。
2.2 最优解:三指针法
更优的解法是使用三指针法(也称为荷兰国旗问题解法),只需要一次遍历就能完成排序。我们维护三个指针:
- left指针:指向当前已排序的0的右边界
- right指针:指向当前已排序的2的左边界
- current指针:当前正在检查的元素
算法步骤如下:
- 初始化left=0,right=len(nums)-1,current=0
- 当current <= right时循环:
a. 如果nums[current] == 0,交换nums[current]和nums[left],left++,current++
b. 如果nums[current] == 1,current++
c. 如果nums[current] == 2,交换nums[current]和nums[right],right--(注意这里current不增加)
2.3 算法正确性证明
这个算法的关键在于:
- left左边的元素都是0(已排序)
- right右边的元素都是2(已排序)
- current从左向右扫描,确保所有元素都被检查
- 当遇到2时,交换后current不增加,因
