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 →The operation does not need to physically shrink nums. It only needs to make its prefix correct: after the method returns k, positions 0 through k - 1 must contain every value different from val. Anything from position k onward is irrelevant, so overwriting unwanted values is enough to remove them logically.
Scan the array from left to right. Whenever you find a value that should remain, place it at the next unused position in the valid prefix. The scan pointer may be ahead of that position because it has passed over values equal to val, while the write pointer advances only when a value survives.
| MEASURE | BOUND | WHY |
|---|---|---|
| Time | O(n) | The loop reads each of the n original positions once. Each position takes one comparison and, for a survivor, one assignment, so no element is revisited or shifted repeatedly. |
| Space | O(1) extra | The two integer indices use constant working memory, and the method modifies nums in place. The output prefix is excluded; even when every value equals val or no value equals val, the working storage remains constant. |
#include <vector>
using namespace std;
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int k = 0;
for (int i = 0; i < static_cast<int>(nums.size()); ++i) {
if (nums[i] != val) {
nums[k++] = nums[i];
}
}
return k;
}
};The important placement is nums[k++] = nums[i]. The read index i keeps moving through the original scan, while k moves only after a non-val value is accepted. When k is less than i, the assignment overwrites an earlier removed value; when k equals i, it simply writes the value back to its original position.
Because the problem permits the surviving values to change order, you can replace a val at the current index with the element at the current end of the not-yet-processed region. Decrease the end immediately, but do not advance the scan pointer after the replacement: the moved value may also equal val and needs another check.
#include <vector>
using namespace std;
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int k = static_cast<int>(nums.size());
int i = 0;
while (i < k) {
if (nums[i] == val) {
nums[i] = nums[k - 1];
--k;
} else {
++i;
}
}
return k;
}
};This is a different arrangement rather than a better asymptotic bound: time remains O(n) and extra space remains O(1). It can perform fewer assignments when many values equal val, but it does not preserve the order of survivors. The stable compaction version is usually easier to reason about; this version is useful when order is explicitly irrelevant and avoiding writes matters.