80. Remove Duplicates from Sorted Array II
An example of two-pointer technique

Problem statement
Given an integer array nums already sorted in non-decreasing order, you must remove duplicates so that each unique element appears at most twice. The relative order of the elements should remain unchanged.
Since changing the array's length in some programming languages is impossible, you must place the result in the first part of the nums array. In other words, if there are k elements after removing the duplicates, the first k elements of nums should contain the final result. Anything beyond the first k elements is not important.
You should return the value of k after placing the final result in the first k slots of the nums array.
The key requirement is to accomplish this task without using extra space for another array. It must be done by modifying the input array nums in-place, using only O(1) extra memory.
Example 1
Input: nums = [1,1,1,2,2,3]
Output: 5, nums = [1,1,2,2,3,_]
Explanation: Your function should return k = 5, with the first five elements of nums being 1, 1, 2, 2, and 3, respectively.
What you leave does not matter beyond the returned k (hence, they are underscores).
Example 2
Input: nums = [0,0,1,1,1,1,2,3,3]
Output: 7, nums = [0,0,1,1,2,3,3,_,_]
Explanation: Your function should return k = 7, with the first seven elements of nums being 0, 0, 1, 1, 2, 3, and 3, respectively.
What you leave does not matter beyond the returned k (hence, they are underscores).
Constraints
1 <= nums.length <= 3 * 10^4.-10^4 <= nums[i] <= 10^4.numsis sorted in non-decreasing order.
Solution 1: Erasing the duplicates
In order for each unique element to appear at most twice, you have to erase the further appearances if they exist.
Since the array nums is sorted, you can determine that existence by checking if nums[i] == nums[i-2] for 2 <= i < nums.length.
Code
#include <vector>
#include <iostream>
using namespace std;
int removeDuplicates(vector<int>& nums)
{
int i = 2;
while (i < nums.size())
{
if (nums[i] == nums[i-2])
{
int j = i;
while (j < nums.size() && nums[j] == nums[i])
{
j++;
}
nums.erase(nums.begin() + i, nums.begin() + j);
}
else
{
i++;
}
}
return nums.size();
}
void printResult(const int k, const vector<int>& nums)
{
cout << k << ", [";
for (int i = 0; i < k ; i++)
{
cout << nums[i] << ",";
}
cout << "]\n";
}
int main()
{
vector<int> nums{1,1,1,2,2,3};
printResult(removeDuplicates(nums), nums);
nums = {0,0,1,1,1,1,2,3,3};
printResult(removeDuplicates(nums), nums);
}
Output:
5, [1,1,2,2,3,]
7, [0,0,1,1,2,3,3,]
Code explanation
Inside the loop, it checks if the element at index
iis equal to the element two positions before it.If the condition is met, there are more than two occurrences of the current element. We need to remove the excess duplicates while preserving two instances. To do this, a second while loop is used until the duplicate elements are no longer found. At this point,
jwill be the index of the first element that differs from the current element.After finding the range of duplicate elements to remove (from index
itoj-1, inclusive), it uses thevector'serasefunction to remove these elements from thenumsarray. This effectively keeps only two instances of the current element.If the condition in step 2 is not met (i.e., there are at most two occurrences of the current element), it moves the index
ito the next unique element in the array.Repeat steps 2 to 4 until
ihas traversed the entire array. The while loop removes all duplicate elements beyond two occurrences while maintaining the order of unique elements.Once the loop finishes, the
numsarray contains unique elements with at most two occurrences of each. Return the size of the modified array usingnums.size().
This solution efficiently removes duplicates from the sorted array by checking for duplicates and erasing the excess occurrences while preserving two instances of each unique element. It then returns the length of the modified array.
Complexity
Runtime:
- Worst case:
O(N^2/3), whereN = nums.size(). The complexity of theerase()method is linear inN. The worst case is whenerase()is called maximumN/3times.
- Worst case:
Example of the worst case:
nums = [1,1,1,2,2,2,3,3,3,4,4,4,5,5,5,6,6,6].
- On average:
O(N)since the number oferase()calls isO(1).
- Extra space:
O(1).
Solution 2: Reassigning the satisfying elements
You might need to avoid the erase() method in the solution above to reduce the complexity. Moreover, after removing the duplicates, the problem only cares about the first k elements of the array nums.
If you look at the final result after removing duplication, the expected nums satisfies
nums[i] > nums[i-2] for 2 <= i < nums.length.
You can use this invariant to reassign the array nums only the satisfied elements.
Code
#include <vector>
#include <iostream>
using namespace std;
int removeDuplicates(vector<int>& nums)
{
if (nums.size() <= 2)
{
return nums.size();
}
int k = 2;
int i = 2;
while (i < nums.size())
{
if (nums[i] > nums[k - 2])
{
nums[k++] = nums[i];
}
i++;
}
return k;
}
void printResult(const int k, const vector<int>& nums)
{
cout << k << ", [";
for (int i = 0; i < k ; i++)
{
cout << nums[i] << ",";
}
cout << "]\n";
}
int main()
{
vector<int> nums{1,1,1,2,2,3};
printResult(removeDuplicates(nums), nums);
nums = {0,0,1,1,1,1,2,3,3};
printResult(removeDuplicates(nums), nums);
}
Output:
Output:
5, [1,1,2,2,3,]
7, [0,0,1,1,2,3,3,]
Code explanation
The code checks the size of the input array
nums. If it has 2 or fewer elements, there's no need to perform any removals, so the function simply returns the size of the original array.It initializes two variables:
k: This will represent the length of the resulting array after removing duplicates (initially set to 2 since we allow up to two occurrences of each element).i: This is an iterator that starts from the array's third element (index 2) and is used to traverse the array.
It starts a loop that iterates from the third element (
i = 2) to the end of the array.Inside the loop, it compares the current element at index
iwith the element atk - 2. This comparison checks if the current element exceeds the previous two positions. If it is, this means it's a new element. Otherwise, it is a third occurrence of the same element, which we want to skip.If the current element is greater than the element at index
k - 2, it updates the element at indexkwith the current element. Then, it incrementskto indicate that a new unique element has been found.Continue iterating through the array by incrementing
i.Once the loop finishes, the array up to index
k - 1contains the unique elements with at most two occurrences each, and the rest of the array can be ignored.Finally, return the value of
k, which represents the length of the resulting array.
Complexity
This solution effectively modifies the input array in-place, removing duplicates that occur more than twice while maintaining the desired order of unique elements. It does so in a single pass through the array, resulting in a time complexity of O(N), where N is the number of elements in the array.
Runtime:
O(N), whereN = nums.size().Extra space:
O(1).
Thanks for reading. Check out my book 10 Classic Coding Challenges for free here.






