用 JavaScript 来实现 LeetCode 75(颜色分类)同样非常经典。针对这道题,这里为你提供两种最核心的解法:
方法一:三指针法(最优解)
这是面试官最希望看到的解法。利用三个指针在数组上原地操作:
- left:指向下一个 0 应该存放的位置。
- right:指向下一个 2 应该存放的位置。
- i:当前遍历的指针。
核心逻辑:
- 当 nums[i] == 0 时,与 left 交换,left 和 i 同时右移。
- 当 nums[i] == 2 时,与 right 交换,right 左移(注意 i 不动,因为从右边换过来的元素还没检查过)。
- 当 nums[i] == 1 时,i 直接右移。
var sortColors = function(nums) {
let left = 0, right = nums.length - 1, i = 0;
while (i <= right) { if (nums[i] === 0) { // 遇到 0,和 left 交换,left 和 i 都前进 [nums[i], nums[left]] = [nums[left], nums[i]]; left++; i++; } else if (nums[i] === 2) { // 遇到 2,和 right 交换,right 后退 // 注意:此时 i 不能前进,因为从右边换过来的元素还没检查 [nums[i], nums[right]] = [nums[right], nums[i]]; right--; } else { // 遇到 1,直接前进 i++; } }};
方法二:计数排序法
由于元素只有 0、1、2 三种,我们可以先统计个数,再重新覆盖数组。这种方法逻辑极其简单,不容易出错。
var sortColors = function(nums) {
// 1. 统计 0, 1, 2 出现的次数
let count = [0, 0, 0];
for (let num of nums) {
count[num]++;
}
// 2. 根据统计结果重写数组 let index = 0; for (let color = 0; color < 3; color++) { for (let j = 0; j < count[color]; j++) { nums[index++] = color; } }};
面试建议:
- 如果是在面试中,强烈建议手写方法一,这能体现你对数组边界和双指针/多指针技巧的扎实掌握。
- 如果在实际工程开发中,且对代码可读性要求更高,方法二是更安全、不易写错的选择。
如果你刚刷完 Rust 版本,对比一下这两种语言的解法,是不是发现 JS 的解构赋值([a, b] = [b, a])写交换逻辑特别优雅?需要我帮你把这几道同类型的“荷兰国旗”变体题也列出来吗?