Problem overview
The method removeRepeats gets an array of integers, nums, and returns a new array in which each value appears only once. It keeps the first copy of each value and drops the later ones, so the values stay in the order they first appear.
For [3, 1, 3, 2, 1] the answer is [3, 1, 2]: the second 3 and the second 1 are repeats. For [6, 6, 6, 6] the answer is [6]. For [4, 9, 2] nothing repeats, so every number stays.
Approach
Read the numbers from left to right, and remember which values have been met. A number that isn't remembered yet is a first copy: put it in the result and remember it. A number that is already remembered is a repeat: skip it.
A Set is the right place to remember values, because has answers "have I seen this value?" quickly, however many values are stored. Reading from left to right is what keeps the first copy and the original order.
Step by step
- Create
seen, an empty set, withnew Set(). - Create
result, an empty array that collects the values to return. - Loop over
numswithfor (let num of nums), from the first number to the last. - Check for a first copy:
!seen.has(num)istruewhennumisn't in the set. The!turns the answer around. - Push
numontoresult. Adding at the end keeps the order of first appearance. - Add
numtoseen, so a later copy is skipped. - Return
resultafter the loop, not inside it, or only the first value would come back.
The solution in JavaScript
class Solution {
removeRepeats(nums) {
let seen = new Set();
let result = [];
for (let num of nums) {
if (!seen.has(num)) {
result.push(num);
seen.add(num);
}
}
return result;
}
}
The array result is the output, and the set seen is only a memory. Keeping them separate matters: a set could hold the values too, but an array is what the method must return.
Why a set and not the result array
You could ask the result array itself, result.includes(num), and it gives the same answer, [3, 1, 2] for the first example. The difference is speed. includes looks at the stored values one by one, so a long array with many different values makes every check slower. A set finds a value without scanning the others, which is why the lesson uses one.
Another way
Because a set already keeps each value once, and keeps them in the order they were added, spreading a set into an array does the same job in one line:
function removeRepeatsShort(nums) {
return [...new Set(nums)];
}
It returns [3, 1, 2], [6] and [4, 9, 2] on the three examples. The longer version is the one the lesson's steps build, and it shows what the set is doing.
Testing
On the statement's examples, the lesson's solution gives these lines, with the values separated by spaces:
3 1 2
6
4 9 2
Common mistakes
- Returning the set's size.
new Set(nums).sizeis the number of different values, 3 for the first example, not the array. - Sorting first.
[3, 1, 3, 2, 1].sort()gives[1, 1, 2, 3, 3], which loses the order of first appearance. Also, with no comparator,sort()sorts numbers as text:[10, 9, 1, 10].sort()gives[1, 10, 10, 9]. - Returning inside the loop. The method would stop after the first value.
- Adding to
seenoutside theif. That is harmless here, but pushing toresultoutside theifkeeps every repeat.
