You are given an integer array nums sorted in non-decreasing order, remove some duplicates in-place such that each unique element appears at most twice. The relative order of the elements should be kept the same.
Since it is impossible to change the length of the array in some languages, you must instead have the result be placed in the first part of the array nums. More formally, if there are k elements after removing the duplicates, then the first k elements of nums should hold the final result. It does not matter what you leave beyond the first k elements.
Return k after placing the final result in the first k slots of nums.
Do not allocate extra space for another array. You must do this by modifying the input array in-place with O(1) extra memory.
Custom Judge:
The judge will test your solution with the following code:
int[] nums = [...]; // Input array
int[] expectedNums = [...]; // The expected answer with correct length
int k = removeDuplicates(nums); // Calls your implementation
assert k == expectedNums.length;
for (int i = 0; i < k; i++) {
assert nums[i] == expectedNums[i];
}If all assertions pass, then your solution will be accepted.
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.
It does not matter what you leave 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.
It does not matter what you leave beyond the returned k (hence they are underscores).
Constraints:
1 <= nums.length <= 30,000-10,000 <= nums[i] <= 10,000nums is sorted in non-decreasing order.Before attempting this problem, you should be comfortable with:
We allow each element to appear at most twice. When we find more than two consecutive duplicates, we shift all subsequent elements left to overwrite the extras. This in-place modification is straightforward but inefficient due to repeated shifting operations.
2 or fewer elements as base cases.class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
n = len(nums)
if n <= 2:
return n
i = 0
while i < n - 1:
if nums[i] == nums[i + 1]:
j = i + 2
cnt = 0
while j < n and nums[i] == nums[j]:
j += 1
cnt += 1
for k in range(i + 2, n):
if j >= n:
break
nums[k] = nums[j]
j += 1
n -= cnt
i += 2
else:
i += 1
return nWe count occurrences of each element using a hash map while preserving order. Then we reconstruct the array, writing each element at most twice. This uses extra space but separates the counting logic from the placement logic.
This approach ensures the array remains sorted since we process unique elements in order.
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
n = len(nums)
if n <= 2:
return n
count = Counter(nums)
i = 0
for num in count:
nums[i] = num
count[num] -= 1
i += 1
if count[num] >= 1:
nums[i] = num
count[num] -= 1
i += 1
return iWe process groups of consecutive duplicates together. For each group, we write at most two copies to the result portion of the array. The left pointer tracks where to write, and the right pointer scans through the array finding groups.
0.r.min(2, count) copies of the element starting at position l.l accordingly and move to the next group.l as the new length.class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
l, r = 0, 0
while r < len(nums):
count = 1
while r + 1 < len(nums) and nums[r] == nums[r + 1]:
r += 1
count += 1
for i in range(min(2, count)):
nums[l] = nums[r]
l += 1
r += 1
return lThe cleanest approach uses a single condition: we only write an element if the write position is less than 2 (first two elements always go through) OR the current element differs from the element two positions back in the result. This automatically limits each value to at most two occurrences.
l at 0.l < 2 or the current element differs from nums[l - 2], write it at position l and increment l.l as the new length.class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
l = 0
for num in nums:
if l < 2 or num != nums[l - 2]:
nums[l] = num
l += 1
return lIn the optimal two-pointer solution, you should compare nums[i] with nums[l - 2], not with nums[l - 1]. Comparing with l - 1 only checks if the current element differs from the previous one, which doesn't prevent more than two consecutive duplicates. You need to look back two positions to ensure at most two occurrences of any value.
Arrays with 2 or fewer elements are already valid (each element can appear at most twice). Some solutions fail to handle these edge cases, leading to index out of bounds errors when checking nums[l - 2] with l < 2. Always either return early for small arrays or use a condition like l < 2 to bypass the comparison.
When using two pointers, the write pointer l should advance only after writing a valid element. A common bug is incrementing l before writing or writing to the wrong index. The pattern should be: check condition, write to nums[l], then increment l. Writing to nums[l++] in languages that support it keeps this atomic.
Sign in to join the discussion