Problem overview
The function removeRepeats gets a vector of integers nums and returns a new vector 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 appear in nums.
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} it is 6. For {4, 9, 2} nothing repeats, so all three numbers stay. The tests print a vector as its values separated by spaces.
Approach
Read the numbers from left to right and remember which values you have met. For each number, one of two things is true:
- it isn't in the memory yet, so this is its first copy: add it to the result and to the memory;
- it is in the memory, so it is a repeat: skip it.
A plain unordered_set can't give back the values in the order they first appeared, so it can't be the answer by itself. That is why there are two containers: the vector result keeps the order, and the set seen answers "have I met this value?" quickly.
Step by step
- Create an empty
unordered_set<int>namedseen. - Create an empty
vector<int>namedresult. - Loop over
numsfrom the first value to the last, with anintnamednum. Reading in order is what keeps the first copy. - Test for a first copy:
seen.count(num) == 0meansnumisn't in the set. - Add it to the end of
resultwithpush_back. - Add it to
seenwithinsert, so that a later copy is skipped. - Return
resultafter the loop.
The solution in C++
class Solution {
public:
vector<int> removeRepeats(vector<int>& nums) {
unordered_set<int> seen;
vector<int> result;
for (int num : nums) {
if (seen.count(num) == 0) {
result.push_back(num);
seen.insert(num);
}
}
return result;
}
};
Notes on the C++:
- The vector is taken by reference, so it isn't copied. The function builds and returns a new vector and leaves
numsas it was. counton a set is 0 or 1, so comparing it with 0 is a membership test. C++17 has nocontains.- Returning
resultby value is cheap: the compiler moves it out.
Complexity
Time is O(n) on average: each number costs one set lookup and, for a first copy, one insert and one push_back, each constant on average. Space is O(n) for the set and the result in the worst case, when every value is different.
Edge cases and common mistakes
- Building a set from the whole vector.
unordered_set<int>(nums.begin(), nums.end())drops the repeats, but the set has no order, so the first-appearance order is lost. - Forgetting to insert into
seen. Then every number looks new and the result is a copy ofnums. - Returning inside the loop. The function would return after the first value.
- Negative numbers and large values. They work the same way; values up to a billion in size fit in an
int.
Testing
{3, 1, 3, 2, 1}gives3 1 2.{6, 6, 6, 6}gives6.{4, 9, 2}gives4 9 2.
