2 POINTERS › TWO POINTER ON ARRAYS
Open — the attempt gate is not wired up yet
This editorial is meant to unlock after you have run the problem at least once, with the worked solution behind one further deliberate click. That needs per-learner unlock state nothing stores today, so for now the whole article is open.
Try it yourself first →Because every value is 0, 1, or 2, a sorted result has a rigid shape: all 0s come first, then all 1s, then all 2s. You do not need to decide the order between arbitrary values. You only need to place each encountered value into its matching region while keeping the unprocessed values available for inspection.
Keep low at the first position that is not known to be a 0, mid at the first position not yet classified, and high at the last position that is not known to be a 2. Values before low are 0, values from low through mid - 1 are 1, and values after high are 2. When mid sees a 2, swap it with high but do not advance mid: the incoming value has not been classified yet.
| MEASURE | BOUND | WHY |
|---|---|---|
| Time | O(n) | mid never moves left, high only moves left, and low only moves right. Each loop either advances mid or decreases high, so there are at most n advances of mid plus n decreases of high rather than repeated scans of the same unknown values. |
| Space | O(1) extra | Only the three indices and a constant number of temporary values are used; nums is modified in place. The bound stays O(1) even for the worst input shape, such as all 0s, all 1s, or all 2s. |
#include <algorithm>
#include <vector>
using namespace std;
class Solution {
public:
void sortColors(vector<int>& nums) {
int low = 0;
int mid = 0;
int high = static_cast<int>(nums.size()) - 1;
while (mid <= high) {
if (nums[mid] == 0) {
swap(nums[low], nums[mid]);
low++;
mid++;
} else if (nums[mid] == 1) {
mid++;
} else {
swap(nums[mid], nums[high]);
high--;
}
}
}
};The most important placement is the missing mid++ in the 2 branch. Swapping with high places the current 2 correctly, but high's old value arrives at mid from the unknown region. The loop must inspect that incoming value next. In contrast, the value swapped into mid from low is already known to be a 1 or a 0-region value, so the 0 branch can safely advance both indices.
#include <vector>
using namespace std;
class Solution {
public:
void sortColors(vector<int>& nums) {
int count[3] = {0, 0, 0};
for (int value : nums) {
count[value]++;
}
int index = 0;
for (int color = 0; color <= 2; color++) {
for (int copies = 0; copies < count[color]; copies++) {
nums[index] = color;
index++;
}
}
}
};Counting is a reasonable arrangement when the problem allows two passes: one pass counts values and a second pass writes the three runs. It still uses O(1) extra space and O(n) time, but it violates this problem's single-pass requirement and temporarily discards the original arrangement. The three-region scan buys compliance with that requirement while preserving the same asymptotic bounds.