0% completed
Solution: Find Non-Duplicate Number Instances
On This Page
Problem Statement
Why this is a Two Pointers problem
Solution
Step-by-Step Algorithm
Algorithm Walkthrough
Code
Complexity Analysis
Time Complexity
Space Complexity
Similar Questions
Solution:
Complexity Analysis
Time Complexity
Space Complexity
Problem Statement
Given an array of numbers sorted in non-decreasing order, remove the duplicates in place so that each distinct value appears only once, keeping the values in sorted order at the front of the array. You may not use any extra space, so the solution must use constant extra space, O(1).
Return k, the number of distinct values. What the array holds beyond the first k positions does not matter and is not checked.
Example 1:
Input: [2, 3, 3, 3, 6, 9, 9]
Output: 4
Explanation: There are four distinct values, so the first four elements become [2, 3, 6, 9]. Whatever sits beyond position 4 is ignored.
Example 2:
Input: [2, 2, 2, 11]
Output: 2
Explanation: There are two distinct values, so the first two elements become [2, 11]. Whatever sits beyond position 2 is ignored.
Constraints:
- 1 <= nums.length <= 3 * 10<sup>4</sup>
-100 <= nums[i] <= 100numsis sorted in non-decreasing order.
Why this is a Two Pointers problem
| What the question says | The signal it matches |
|---|---|
| "an array of numbers sorted in non-decreasing order", repeated in the constraints | the input is sorted |
| "in place", and "not use any extra space, so the solution must use constant extra space" | the question says in place or constant extra space |
| "remove the duplicates ... so that each distinct value appears only once" | a duplicate rule, one of the conditions this pattern handles |
Nothing is being searched for from both ends, so this is not the converging shape. One pointer reads ahead while the other writes behind it, which is the same direction variant.
The closest alternative. A hash set is the usual way to remove duplicates. That is the Hash Maps pattern. Two facts rule it out here.
The array is sorted, so duplicates are already next to each other. Nothing has to be remembered. Extra space is also forbidden, and a set needs it.
Solution
In this problem, we need to separate the duplicate elements in-place such that the resultant length of the array remains sorted. As the input array is sorted, one way to do this is to shift the elements left whenever we encounter duplicates. In other words, we will keep one pointer for iterating the array and one pointer for placing the next non-duplicate number. So our algorithm will be to iterate the array and whenever we see a non-duplicate number we move it next to the last non-duplicate number we've seen.
Step-by-Step Algorithm
- Initialize the Index: Start by initializing a variable
nextNonDuplicateto 1. This variable will keep track of the position where the next unique element should be placed. - Iterate Through the Array: Loop through the array to the end. The code starts the reading index at 0, which costs one comparison of the first element against itself and keeps the loop body uniform.
- Compare Elements: For each element, check if it is different from the element at the position
nextNonDuplicate - 1.- If Different: If the current element is different from the element at
nextNonDuplicate - 1, copy the current element to the positionnextNonDuplicate. - Increment Index: Increase the
nextNonDuplicateindex by 1 to point to the next position for a unique element.
- If Different: If the current element is different from the element at
- Return Result: After completing the iteration, return the value of
nextNonDuplicate, which represents the number of unique elements in the array.
Algorithm Walkthrough
The array [2, 3, 3, 3, 6, 9, 9] is sorted, so equal values sit next to each other. One pointer reads ahead and the other marks where the next distinct value should be written. The first value is always distinct, so the writer starts at index 1.
1 of 8
Code
Here is what our algorithm will look like:
Complexity Analysis
Time Complexity
- Loop through the array: The algorithm uses a single
forloop to iterate through the array. Each element is processed once, so the time complexity of the loop is O(N), whereNis the number of elements in the array. - Comparison and assignment: Inside the loop, the comparison
arr[nextNonDuplicate - 1] != arr[i]and the assignmentarr[nextNonDuplicate] = arr[i]are both constant time operations, O(1).
Overall time complexity: O(N).
Space Complexity
- In-place modification: The algorithm modifies the input array in place and only uses a few extra variables (
nextNonDuplicateandi), which require constant space. - Since no additional data structures are used that scale with the input size, the space complexity is O(1).
Overall space complexity: O(1).
Similar Questions
Problem 1: Given an unsorted array of numbers and a target key, remove all instances of key in-place and return the new length of the array.
Example 1:
Input: [3, 2, 3, 6, 3, 10, 9, 3], Key=3
Output: 4
Explanation: The first four elements after removing every 'Key' will be [2, 6, 10, 9].
Example 2:
Input: [2, 11, 2, 2, 1], Key=2
Output: 2
Explanation: The first two elements after removing every 'Key' will be [11, 1].
Solution:
This problem is quite similar to our parent problem. We can follow a two-pointer approach and shift numbers left upon encountering the key. Here is what the code will look like:
Complexity Analysis
Time Complexity
- Loop through the array: The algorithm uses a single
forloop to iterate through the array. Each element is processed exactly once, resulting in a time complexity of O(N), whereNis the number of elements in the array. - Comparison and assignment: Inside the loop, the comparison
arr[i] != keyand the assignmentarr[nextElement] = arr[i]are both constant-time operations, O(1).
Overall time complexity: O(N).
Space Complexity
- In-place modification: The algorithm modifies the input array in place and only uses a few extra variables (
nextElementandi), which require constant space. - Since no additional data structures are used, the space complexity is O(1).
Overall space complexity: O(1).
Gaurav Thapliyal
· 3 months ago
The problem is a bit confusing. To be honest we do not even need to swap the elements as ultimately we are returning the length of array with unique elements. Can be done by tracking with a length pointer
Gaurav Thakur
· 5 months ago
To Justify the statement "Move all the unique number instances at the beginning of the array and after moving return the length of the subarray that has no duplicate in it.", It has to move the elements, not just count.
Another problem is with the test cases. If input is empty array, it is expecting 1 as output. Logically, in that case it should be 0.
class Solution {
public int moveElements(int[] arr) {
if(arr.length < 2) {
return arr.length;
}
int index = 1;
int ndi = 0;
while(index < arr.length) {
if(arr[index] == arr[ndi]) {
index++;
} else {
if(index != ndi+1) {
swap(arr, index, ndi+1);
}
index++;
ndi++;
}
}
return ndi + 1;
}
private void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
beruss sama
· 5 months ago
class Solution: def moveElements(self, arr): ans = 0 for i in range(1, len(arr)): if arr[i] != arr[i-1]: ans += 1 return 1 + ans
David Bishop
· 6 months ago
I wasted so much time on this question even though i had the solution almost immediately because it said you had to actually move the items in the array, so i figured it was required. Should have known since the array is never returned its functionally the same to just count the non duplicates.
wasim ahmed
· 6 months ago
class Solution: def moveElements(self, arr): # TODO: Write your code here n = len(arr) for curr in range(n): nxt = curr + 1 while nxt < n and arr[curr] >= arr[nxt]: nxt += 1 if nxt == n: break if nxt < n and arr[curr] < arr[nxt]: arr[curr+1], arr[nxt] = arr[nxt], arr[curr + 1] return curr + 1
anjoiype
· a year ago
The problem says return the number of non duplicates. For e.g. [1,1,2,3,3,4,5,5,5]. Here the non duplicate numbers are 2 and 4. Rest all are duplicated. So the answer should be 2 instead of 5
Rahil Dhodapkar
· 2 years ago
class Solution:
def moveElements(self, arr):
write_idx = 1
curr_val = arr[0]
for read_idx in range(1, len(arr)):
if arr[read_idx] > curr_val:
curr_val = arr[read_idx]
arr[write_idx], arr[read_idx] = arr[read_idx], arr[write_idx]
write_idx += 1
return write_idx
monir.imamverdi
· 2 years ago
This page needs to be rewritten, it's so confusing.
We're expecting the first occurrence of each distinct number to be retained in the final output, rather than only keeping numbers that appear exactly once. That means instead of filtering strictly unique elements, we need to retain distinct elements in their first occurrence while shifting them to the front.
Razvan
· 2 years ago
class Solution { moveElements(arr) { return [...new Set(arr)].length; } }
Nabeel Keblawi
· 2 years ago
I know we're using 2 pointers and that was my initial solution, but the challenge was it kept swapping even after all non-duplicate values were found. So I found an easier shortcut with one line of code:
return len(set(arr))
And it passed all test cases. But if we insist on using two pointers to solve this one, I'd go with the provided solution.
Reading Progress
0%
On This Page
Problem Statement
Why this is a Two Pointers problem
Solution
Step-by-Step Algorithm
Algorithm Walkthrough
Code
Complexity Analysis
Time Complexity
Space Complexity
Similar Questions
Solution:
Complexity Analysis
Time Complexity
Space Complexity