1. Problem
Given an array of integers that are not strictly incrementally sortednums
,please,In placeDelete duplicate elements so that each element isOnly appear once. Returns the new length of the array after deletion.
Require:
-
Modified in place:The input array must be modified directly.
nums
. No extra space is allowed. - Relative order:The relative order between elements must be consistent.
-
Returns the number of unique elements:Returns the number of unique elements in the array
k
。 -
Array content:Array
nums
The frontk
Elements should contain unique elements and as they were originally innums
The order in which it appears.nums
Subscript in arrayk
The contents of the subsequent parts can be modified arbitrarily, and their value will not affect the result.
Example:
Input: nums = [1,1,2]
Output: 2, nums = [1,2,_] // Underscore indicates unimportant position
Input: nums = [0,0,1,1,1,2,2,3,3,4]
Output: 5, nums = [0,1,2,3,4,,,,,_]
explain:
The function should return a new lengthk = 5
, andnums
The first five elements are0, 1, 2, 3, 4
. No need to consider elements in the array beyond the new length.
Key points:
- Non-strict increment:Meaning that the array is sorted, but not necessarily in strict ascending order (repeated elements are allowed).
- Delete in place:The space complexity must be O(1).
- The relative order remains unchanged:After deleting duplicate elements, the order of the remaining elements must be the same as in the original array.
2. Problem analysis
Core Objectives:Remove duplicate elements from the sorted array, making sure each unique element only appears once, and returns the number of unique elements.
Constraints:
- Operation in place:This is the most critical constraint. We cannot create new arrays to store results. The original array must be modified directly.
- Relative order:After deleting duplicates, the relative order of the unique elements must be consistent with the original array.
- Sorting features:The input array is sorted. This is an important premise that allows us to use more efficient algorithms.
Problem solution:Since the array is sorted, you can use the double pointer method to solve this problem. The double pointer method is usually used for in-situ operation and is efficient.
-
Slow pointer (
i
):Point to where the next non-repeat element should be placed. -
Fast pointer (
j
):Used to traverse arrays and find non-repetitive elements.
Algorithm steps:
-
initialization:
-
i = 0
(Slow pointer, pointing to the first position of the array, i.e. where the first unique element should be placed). -
j = 1
(Fast pointer, traversal from the second position of the array).
-
-
Iterate over the array:
- use
j
Transfer the arraynums
。 -
if
nums[j] != nums[i]
:illustratenums[j]
is a new only element.- Will
i
Move one forward (i++
)。 - Will
nums[j]
Copy tonums[i]
Location (nums[i] = nums[j]
)。
- Will
-
Otherwise (if
nums[j] == nums[i]
):illustratenums[j]
is a repeating element, skip it.
- use
-
Return result:After the cycle ends,
i + 1
It is the number of unique elements in the array (becausei
is the index, starting from 0).
Sample demonstration:Assumptionnums = [0, 0, 1, 1, 1, 2, 2, 3, 3, 4]
step | i | j | nums | illustrate |
---|---|---|---|---|
1 | 0 | 1 | [0, 0, 1, 1, 1, 2, 2, 3, 3, 4] |
initialization |
2 | 0 | 2 | [0, 0, 1, 1, 1, 2, 2, 3, 3, 4] |
nums[2] != nums[0] , i++ , nums[1] = nums[2]
|
3 | 1 | 3 | [0, 1, 1, 1, 1, 2, 2, 3, 3, 4] |
nums[3] != nums[1] , i++ , nums[2] = nums[3]
|
4 | 2 | 4 | [0, 1, 2, 1, 1, 2, 2, 3, 3, 4] |
nums[4] != nums[2] , i++ , nums[3] = nums[4]
|
5 | 3 | 5 | [0, 1, 2, 1, 1, 2, 2, 3, 3, 4] |
nums[5] != nums[3] , i++ , nums[4] = nums[5]
|
6 | 4 | 6 | [0, 1, 2, 3, 1, 2, 2, 3, 3, 4] |
nums[6] != nums[4] , i++ , nums[5] = nums[6]
|
7 | 5 | 7 | [0, 1, 2, 3, 4, 2, 2, 3, 3, 4] |
nums[7] != nums[5] , i++ , nums[6] = nums[7]
|
8 | 6 | 8 | [0, 1, 2, 3, 4, 3, 2, 3, 3, 4] |
nums[8] != nums[6] , i++ , nums[7] = nums[8]
|
9 | 7 | 9 | [0, 1, 2, 3, 4, 3, 3, 3, 3, 4] |
nums[9] != nums[7] , i++ , nums[8] = nums[9]
|
10 | 8 | 10 | [0, 1, 2, 3, 4, 3, 3, 3, 4, 4] |
End of the loop |
Final result:nums = [0, 1, 2, 3, 4, ...]
,returni + 1 = 5
Complexity analysis:
- Time complexity:O(n), where n is the length of the array. We need to iterate over the array once.
- Space complexity:O(1), operates in place, only use additional space at the constant level.
III. Algorithm implementation
Since the array is sorted, you can use the double pointer method to solve this problem.
- Initialize the fast and slow pointer。
- Iterate through the array。
- Return result。
class Solution { public: int removeDuplicates(vector<int>& nums) { if (() < 2) return (); int left = 0; int right = 1; while (right < ()) { if (nums[right] == nums[left]) ++right; else nums[++left] = nums[right++]; } return left + 1; } };
4. Problem variant: keep it twice at most
Delete redundant duplicates in an ordered array (maximum two retained):Given a sorted arraynums
,pleaseIn placeDelete the repeated elements so that each element appears at most twice. Returns the new length of the array after deletion.
Require:
-
Modified in place:The input array must be modified directly.
nums
. No additional array space is allowed. - O(1) Extra space:This must be done with the extra space complexity of O(1).
- Relative order:The relative order of elements must be consistent.
-
Return value:Returns the new length of the array after deleting the duplicate elements
k
。 -
Array content:Array
nums
The frontk
Elements should contain processed elements, exceedingk
The length part can be ignored.
Example:
Input: nums = [1,1,1,2,2,3]
Output: 5, nums = [1,1,2,2,3,_] // Underscore indicates unimportant position
Input: nums = [0,0,0,1,1,1,2,2,3,3,4]
Output: 9, nums = [0,0,1,1,2,2,3,3,4,_]
illustrate:
- For
nums = [1,1,1,2,2,3]
, the function should return the new lengthk = 5
, andnums
The first five elements are1, 1, 2, 2, 3
。 - For
nums = [0,0,0,1,1,1,2,2,3,3,4]
, the function should return the new lengthk = 9
, andnums
The first nine elements are0, 0, 1, 1, 2, 2, 3, 3, 4
。
Key points:
- Ordered array:The input array is sorted, and using this feature to optimize the algorithm.
- Keep it up to twice:Each element is allowed to appear at most twice.
- Modify in place + O(1):The choice of algorithms is limited, and an algorithm with constant spatial complexity must be used.
V. Analysis and code implementation
5.1. Problem analysis
The problem can be broken down into the following sub-problems:
- Identify duplicates:How to effectively identify recurring elements? Since the array is ordered, the same adjacent elements are repeated.
- count:How to record the number of occurrences of each element? A variable is needed to track the number of occurrences of the current element.
- Modified in place:How to move elements that need to be retained to the front of the array without using extra space? Using the double pointer method is key.
- Update length:How to calculate and return the modified array length? The final position of the slow pointer + 1 is the new length.
Algorithm ideas:Based on the dual pointer method, combined with counters to solve this problem.
-
Slow pointer (
i
):Point to where the next element to be retained should be placed. -
Fast pointer (
j
):Used to traverse the array and check whether the element should be preserved. -
counter(
count
):Records the number of consecutive occurrences of the current element.
5.2. Algorithm implementation
Algorithm steps:
-
initialization:
-
i = 0
(Slow pointer) -
j = 0
(Fast pointer) -
count = 1
(The initial count is 1, becausenums[0]
Appear at least once)
-
-
Iterate over the array:
- Loop
j
From 1 to- 1
。 -
Situation 1:
nums[j] == nums[j-1]
(Encounter with the same element)-
count++
(Increase the counter). -
if
count <= 2
:Indicates that the current element is allowed to be retained.- Will
nums[j]
Copy tonums[i]
Location (nums[i] = nums[j]
)。 -
i++
(Move slow pointer).
- Will
-
-
Situation 2:
nums[j] != nums[j-1]
(Encounter different elements)nums[i] = nums[j]
i++
count=1
- Loop
Return result:After the cycle ends,
i
It is the number of elements that should be retained in the array, so it returnsi
。
Sample demonstration:Assumptionnums = [1,1,1,2,2,3]
step | i | j | count | nums | illustrate |
---|---|---|---|---|---|
1 | 0 | 0 | 1 | [1, 1, 1, 2, 2, 3] |
initialization |
2 | 0 | 1 | 2 | [1, 1, 1, 2, 2, 3] |
nums[1] == nums[0] , count++ , count <= 2 , nums[0] = nums[1] , i++
|
3 | 1 | 2 | 3 | [1, 1, 1, 2, 2, 3] |
nums[2] == nums[1] , count++ , count > 2 ,jump over |
4 | 1 | 3 | 1 | [1, 1, 1, 2, 2, 3] |
nums[3] != nums[2] , count = 1 , nums[1] = nums[3] , i++ |
5 | 2 | 4 | 2 | [1, 2, 1, 2, 2, 3] |
nums[4] == nums[3] , count++ , count <= 2 , nums[2] = nums[4] , i++
|
6 | 3 | 5 | 1 | [1, 2, 2, 2, 2, 3] |
nums[5] != nums[4] , count = 1 , nums[3] = nums[5] , i++ |
Final result:nums = [1, 1, 2, 2, 3, ...]
,returni = 5
class Solution { public: int removeDuplicates(vector<int>& nums) { int n = (); if (n < 3) return n; int left = 1; int count = 1; for (int right = 1; right < n; ++right) { if (nums[right - 1] == nums[right]) { ++count; if (count <= 2) { nums[left] = nums[right]; ++left; } } else { nums[left] = nums[right]; ++left; count = 1; } } return left; } };
Complexity analysis:
- Time complexity:O(n), where n is the length of the array. It takes time to traverse the array.
-
Space complexity:O(1), using additional space at constant level (
i
,j
,count
)。
5.3. Fast and Slow Pointer (recommended)
principle:
-
slow
The initial value of the pointer is 2 because it means that the first two elements in the new array have been determined (i.e. the first two elements of the original array). -
fast
The pointer starts traversing the array from 2. - if
nums[fast]
andnums[slow - 2]
Unequal, it meansnums[fast]
can be added to a new array and assigned tonums[slow]
, and increment at the same timeslow
Pointer. - if
nums[fast]
andnums[slow - 2]
Equal, it meansnums[fast]
It is an extra repeating element, skip it directly. - After the cycle ends,
slow
The value of the pointer is the length of the new array.
Sample demonstration:Assumptionnums = [1,1,1,2,2,3]
step | slow | fast | nums | illustrate |
---|---|---|---|---|
1 | 2 | 2 | [1, 1, 1, 2, 2, 3] |
initialization |
2 | 2 | 3 | [1, 1, 1, 2, 2, 3] |
nums[3] != nums[slow - 2] (2 != 1),nums[slow] = nums[fast] (nums[2] = 2),slow++
|
3 | 3 | 4 | [1, 1, 2, 2, 2, 3] |
nums[4] != nums[slow - 2] (2 != 1),nums[slow] = nums[fast] (nums[3] = 2),slow++
|
4 | 4 | 5 | [1, 1, 2, 2, 2, 3] |
nums[5] != nums[slow - 2] (3 != 2),nums[slow] = nums[fast] (nums[4] = 3),slow++
|
Final result:nums = [1, 1, 2, 2, 3, ...]
,returnslow = 5
Code implementation:
class Solution { public: int removeDuplicates(vector<int>& nums) { int n = (); if (n <= 2) { return n; // Relative to less than or equal to two elements, return directly } int slow = 2; // The slow pointer points to the next position to be placed, starting from the third position int fast = 2; // Fast pointer is used to traverse arrays while (fast < n) { // If the current element is different from the first two elements of the slow pointer, it can be preserved if (nums[fast] != nums[slow - 2]) { nums[slow] = nums[fast]; // Move the element pointed to by the fast pointer to the position of the slow pointer slow++; // The slow pointer moves backward } fast++; // The fast pointer always moves backward } return slow; // The value of the slow pointer is the length of the new array } };
Complexity analysis:
- Time complexity:O(n), where n is the length of the array. You only need to iterate over the array once.
-
Space complexity:O(1), using additional space at constant level (
slow
,fast
)。
5.4. Inefficient code implementation
Idea: For repeating elements over 2 times, use a loop to move them to the end of the array using a loop.
The idea is correct, but there are some efficiency problems and potential mistakes. The core problem is that for each element that needs to be deleted, a loop move operation is performed, which will lead to excessive time complexity, especially when there are many repeating elements.
class Solution { public: int removeDuplicates(vector<int>& nums) { int n = (); if (n < 3) return n; int left = 0; for (int right = 1; right < n; ++right) { if (nums[left] != nums[right]) { left = right; continue; } if (right - left > 1) { for (int i = right - 1; i < (n - 1); ++i) std::swap(nums[i], nums[i + 1]); --n; --right; } } return n; } };
6. Summary
The double pointer method is an effective way to solve such in-situ modification problems. By maintaining two pointers, one pointing to the position of the next unique element and the other for iterating through the array, we can efficiently delete duplicates and keep the relative order unchanged. Understanding the characteristics of sorting arrays is crucial to selecting the right algorithm.
The above is the detailed content of N methods for C++ to delete ordered array duplicates in place. For more information about C++ deleting ordered array duplicates, please pay attention to my other related articles!