一、稳定性是这道题的关键约束
LeetCode 2161 要求把数组按 pivot 分成三部分:小于、等于、大于,且保持相对顺序不变。
这个约束直接排除了经典的荷兰国旗双指针交换解法。交换会打乱元素的原始顺序,而这道题恰好需要"稳定分区"。
二、两种解法
解法一:三次遍历
javascript
var pivotArray = function(nums, pivot) {
const n = nums.length, ans = new Array(n);
let idx = 0;
for (let i = 0; i < n; i++) if (nums[i] < pivot) ans[idx++] = nums[i];
for (let i = 0; i < n; i++) if (nums[i] === pivot) ans[idx++] = nums[i];
for (let i = 0; i < n; i++) if (nums[i] > pivot) ans[idx++] = nums[i];
return ans;
};
解法二:一次遍历 + 三数组
javascript
var pivotArray = function(nums, pivot) {
const less = [], equal = [], greater = [];
for (const num of nums) {
if (num < pivot) less.push(num);
else if (num === pivot) equal.push(num);
else greater.push(num);
}
return [...less, ...equal, ...greater];
};
两种解法都是 O(n) 时间 + O(n) 空间。第一种内存访问更连续,第二种写法更简洁。
三、荷兰国旗的交换为什么不适用
荷兰国旗问题用三指针一次遍历完成分区:
javascript
let i = 0, left = 0, right = n - 1;
while (i <= right) {
if (nums[i] < pivot) [nums[i++], nums[left++]] = [nums[left], nums[i]];
else if (nums[i] > pivot) [nums[i], nums[right--]] = [nums[right], nums[i]];
else i++;
}
这段代码正确地将数组分成了三部分,但不保证稳定性------因为交换操作无法维持元素间的相对顺序。当一个元素被 swap 到后面时,它和后续元素的关系就变了。
四、总结
- 稳定分区要求排除了双指针交换,只能用顺序收集
- 三次遍历和一次遍历+三数组本质等价
- 这道题的核心不是"如何分区",而是"在稳定的前提下如何分区"
- 理解稳定性的含义,比记住解法更重要