Problem overview
The method removeRepeats receives an array of integers, nums, and returns a new array in which each value appears once. The first copy of each value stays, later copies are dropped, and the values keep the order in which they first appeared. The input has at least one number, each between -1,000,000,000 and 1,000,000,000.
For [3, 1, 3, 2, 1] the result is [3, 1, 2]: the second 3 and the second 1 are repeats. For [6, 6, 6, 6] the result is [6], and for [4, 9, 2] nothing repeats, so every number stays.
Approach: remember what you have seen
Read the numbers from left to right. For each one, ask whether it has appeared before. If not, it is a first copy: put it in the result and remember it. If so, skip it. Reading in order is what guarantees that the kept copy is the first one and that the order is preserved.
The question "have I seen this value?" is what a Set answers quickly. An array's includes would work too, but it looks at the values one by one, so the set is the better tool.
Step by step
- Create
seen, an emptySet<number>, for the values met so far. - Create
result, an emptynumber[], for the values to return. - Loop over
numswithfor...of, from first to last. - Test
!seen.has(num). The!turns the answer around, so the test is true only for a value that is new. - Push
numontoresult. Adding at the end keeps the order of first appearance. - Add
numtoseen, so that its later copies are skipped. - Return
resultafter the loop. Returning inside the loop would send back only the first value.
The solution in TypeScript
class Solution {
removeRepeats(nums: number[]): number[] {
let seen: Set<number> = new Set();
let result: number[] = [];
for (let num of nums) {
if (!seen.has(num)) {
result.push(num);
seen.add(num);
}
}
return result;
}
}
Some details:
new Set()with a type annotation. The annotationSet<number>on the variable tells TypeScript what the set holds. Types are erased when the code compiles, so the set itself holds whatever you add.- A shorter way.
[...new Set(nums)]also drops repeats and keeps first-appearance order, because a set remembers insertion order. For[3, 1, 3, 2, 1]it gives[3,1,2]. The lesson builds the longer version so you see each step. - Negative numbers and large values are ordinary values for a set.
[-5, 0, -5, 1000000000, 1000000000]gives[-5,0,1000000000].
Edge cases and common mistakes
- Adding to
seenbefore the test. Ifseen.add(num)comes before theif, the value is always already there, the test is never true, and the result stays empty. - Sorting first. Sorting would bring equal values together, but it destroys the order the task wants to keep.
- Returning the set. The method returns an array, so the set is only a helper.
- Equal values that are not next to each other. The set remembers every value met so far, not just the previous one, so in
[3, 1, 3, 2, 1]the second 3 is caught even though a 1 sits between the two 3s. Comparing each number only with its neighbour would miss it. - Single value. An array with one number returns an array with that number.
Testing
[3, 1, 3, 2, 1]gives[3, 1, 2].[6, 6, 6, 6]gives[6].[4, 9, 2]gives[4, 9, 2].
