Remove Duplicates from Sorted Array
Problem Statement
Section titled “Problem Statement”Given an integer array nums sorted in non-decreasing order, remove the duplicates in-place such that each unique element appears only once. The relative order of the elements should be kept the same. Then return the number of unique elements in nums.
Consider the number of unique elements of nums to be k. To get accepted, you need to do the following things:
- Change the array
numssuch that the firstkelements ofnumscontain the unique elements in the order they were present initially. - The remaining elements of
numsare not important as well as the size ofnums. - Return
k.
Examples
Section titled “Examples”| Input | Output | Explanation |
|---|---|---|
[1, 1, 2] | 2 | Array becomes [1, 2, _]. The first 2 elements are unique. |
[0, 0, 1, 1, 1, 2, 2, 3, 3, 4] | 5 | Array becomes [0, 1, 2, 3, 4, _, _, _, _, _]. The first 5 elements are unique. |
Constraints
Section titled “Constraints”1 <= nums.length <= 3 * 10^4-100 <= nums[i] <= 100numsis sorted in non-decreasing order.
Real-World Applications
Section titled “Real-World Applications”Complexity Comparison
Section titled “Complexity Comparison”| Approach | Time | Space | Modifies Array | Best When |
|---|---|---|---|---|
| Two Pointers In-Place | O(n) | O(1) | Yes | General case — single pass, no extra memory |
| Simple Pass | O(n) | O(1) | Yes | Clarity over performance — easier to understand |
Which approach should you learn first?
Section titled “Which approach should you learn first?”- Pick Two Pointers if you want the optimal, interview-ready solution.
- Pick Simple Pass if you prefer clearer variable naming and explicit logic flow.
Approach 1: Two Pointers In-Place
Section titled “Approach 1: Two Pointers In-Place”Use two pointers: one to read unique elements and one to write them back. Since the array is sorted, duplicates are always consecutive. When we encounter a new unique element, write it to the write pointer and advance it.
The key insight is that we only need to check nums[i] != nums[i - 1]. If true, we found a new unique element and should write it to the position k.
Step-by-step Example
Section titled “Step-by-step Example”Input: nums = [1, 1, 2]
| Step | i | nums[i] | nums[i-1] | Same? | Action | k | Array State |
|---|---|---|---|---|---|---|---|
| Start | - | - | - | - | Initialize | 1 | [1, 1, 2] |
| 1 | 1 | 1 | 1 | ✓ | Skip, duplicate | 1 | [1, 1, 2] |
| 2 | 2 | 2 | 1 | ✗ | Write nums[2] to nums[k=1], k++ | 2 | [1, 2, 2] |
Return k = 2, array first 2 elements: [1, 2] ✓
Input: nums = [0, 0, 1, 1, 1, 2, 2, 3, 3, 4]
| Step | i | nums[i] | Unique? | Action | k | Progress |
|---|---|---|---|---|---|---|
| Start | - | - | - | Initialize | 1 | 0 at k=0 is unique |
| 1 | 1 | 0 | No | Skip | 1 | No change |
| 2 | 2 | 1 | Yes | Write to k=1, k++ | 2 | [0, 1, ...] |
| 3 | 3 | 1 | No | Skip | 2 | No change |
| 4 | 4 | 1 | No | Skip | 2 | No change |
| 5 | 5 | 2 | Yes | Write to k=2, k++ | 3 | [0, 1, 2, ...] |
| 6 | 6 | 2 | No | Skip | 3 | No change |
| 7 | 7 | 3 | Yes | Write to k=3, k++ | 4 | [0, 1, 2, 3, ...] |
| 8 | 8 | 3 | No | Skip | 4 | No change |
| 9 | 9 | 4 | Yes | Write to k=4, k++ | 5 | [0, 1, 2, 3, 4, ...] |
Return k = 5 ✓
Animated walkthrough
Watch the write pointer (k) move forward only when a unique element is found. The read pointer (i) scans through the entire array.
Pseudocode
Section titled “Pseudocode”function removeDuplicates(nums): if nums is empty: return 0
k = 1 // First element is always unique for i from 1 to len(nums) - 1: if nums[i] != nums[i - 1]: nums[k] = nums[i] k = k + 1
return kSolution Code
Section titled “Solution Code”from typing import List
def removeDuplicates(nums: List[int]) -> int: """ Two-Pointer In-Place Approach Remove duplicates from sorted array in-place and return the length of the new array.
Time Complexity: O(n) Space Complexity: O(1) """ if not nums: return 0
k = 1 # First element is always unique for i in range(1, len(nums)): if nums[i] != nums[i - 1]: nums[k] = nums[i] k += 1
return k
# Test casesprint(removeDuplicates([1, 1, 2])) # 2, nums = [1, 2, _]print(removeDuplicates([0, 0, 1, 1, 1, 2, 2, 3, 3, 4])) # 5, nums = [0, 1, 2, 3, 4, _, _, _, _, _]#include <iostream>#include <vector>
int removeDuplicates(std::vector<int>& nums) { /* Two-Pointer In-Place Approach Remove duplicates from sorted array in-place and return the length of the new array.
Time Complexity: O(n) Space Complexity: O(1) */ if (nums.empty()) { return 0; }
int k = 1; // First element is always unique for (int i = 1; i < (int)nums.size(); i++) { if (nums[i] != nums[i - 1]) { nums[k] = nums[i]; k++; } }
return k;}
int main() { std::vector<int> nums1 = {1, 1, 2}; std::cout << removeDuplicates(nums1) << std::endl; // 2, nums = [1, 2, _]
std::vector<int> nums2 = {0, 0, 1, 1, 1, 2, 2, 3, 3, 4}; std::cout << removeDuplicates(nums2) << std::endl; // 5, nums = [0, 1, 2, 3, 4, _, _, _, _, _]
return 0;}public class RemoveDuplicatesFromSortedArrayTwoPointer { /* Two-Pointer In-Place Approach Remove duplicates from sorted array in-place and return the length of the new array.
Time Complexity: O(n) Space Complexity: O(1) */ public static int removeDuplicates(int[] nums) { if (nums == null || nums.length == 0) { return 0; }
int k = 1; // First element is always unique for (int i = 1; i < nums.length; i++) { if (nums[i] != nums[i - 1]) { nums[k] = nums[i]; k++; } }
return k; }
public static void main(String[] args) { int[] nums1 = {1, 1, 2}; System.out.println(removeDuplicates(nums1)); // 2, nums = [1, 2, _]
int[] nums2 = {0, 0, 1, 1, 1, 2, 2, 3, 3, 4}; System.out.println(removeDuplicates(nums2)); // 5, nums = [0, 1, 2, 3, 4, _, _, _, _, _] }}/** * Two-Pointer In-Place Approach * Remove duplicates from sorted array in-place and return the length of the new array. * * Time Complexity: O(n) * Space Complexity: O(1) * * @param {number[]} nums * @return {number} */function removeDuplicates(nums) { if (nums.length === 0) { return 0; }
let k = 1; // First element is always unique for (let i = 1; i < nums.length; i++) { if (nums[i] !== nums[i - 1]) { nums[k] = nums[i]; k++; } }
return k;}
// Test casesconsole.log(removeDuplicates([1, 1, 2])); // 2, nums = [1, 2, _]console.log(removeDuplicates([0, 0, 1, 1, 1, 2, 2, 3, 3, 4])); // 5, nums = [0, 1, 2, 3, 4, _, _, _, _, _]/*Two-Pointer In-Place ApproachRemove duplicates from sorted array in-place and return the length of the new array.
Time Complexity: O(n)Space Complexity: O(1)*/pub fn remove_duplicates(nums: &mut Vec<i32>) -> i32 { if nums.is_empty() { return 0; }
let mut k = 1; // First element is always unique for i in 1..nums.len() { if nums[i] != nums[i - 1] { nums[k] = nums[i]; k += 1; } }
k as i32}
fn main() { let mut nums1 = vec![1, 1, 2]; println!("{}", remove_duplicates(&mut nums1)); // 2, nums = [1, 2, _]
let mut nums2 = vec![0, 0, 1, 1, 1, 2, 2, 3, 3, 4]; println!("{}", remove_duplicates(&mut nums2)); // 5, nums = [0, 1, 2, 3, 4, _, _, _, _, _]}package main
import "fmt"
/*Two-Pointer In-Place ApproachRemove duplicates from sorted array in-place and return the length of the new array.
Time Complexity: O(n)Space Complexity: O(1)*/func removeDuplicates(nums []int) int { if len(nums) == 0 { return 0 }
k := 1 // First element is always unique for i := 1; i < len(nums); i++ { if nums[i] != nums[i-1] { nums[k] = nums[i] k++ } }
return k}
func main() { nums1 := []int{1, 1, 2} fmt.Println(removeDuplicates(nums1)) // 2, nums = [1, 2, _]
nums2 := []int{0, 0, 1, 1, 1, 2, 2, 3, 3, 4} fmt.Println(removeDuplicates(nums2)) // 5, nums = [0, 1, 2, 3, 4, _, _, _, _, _]}Approach 2: Simple Pass
Section titled “Approach 2: Simple Pass”Instead of tracking indices i and k, use explicit readIdx and writeIdx pointers with clearer semantics. This approach is functionally identical to the first but with more descriptive variable names.
Step-by-step Example
Section titled “Step-by-step Example”Input: nums = [1, 1, 2]
| readIdx | writeIdx | nums[readIdx] | nums[writeIdx] | Action | Result |
|---|---|---|---|---|---|
| Start | 0 | - | 1 | Initialize pointers | - |
| 1 | 0 | 1 | 1 | Equal, skip | No change |
| 2 | 0 | 2 | 1 | Different, write nums[2] to nums[1], writeIdx++ | [1, 2, _] |
Return writeIdx + 1 = 2 ✓
Pseudocode
Section titled “Pseudocode”function removeDuplicates(nums): if nums is empty: return 0
writeIdx = 0 for readIdx from 1 to len(nums) - 1: if nums[readIdx] != nums[writeIdx]: writeIdx = writeIdx + 1 nums[writeIdx] = nums[readIdx]
return writeIdx + 1Solution Code
Section titled “Solution Code”from typing import List
def removeDuplicates(nums: List[int]) -> int: """ Simple Pass Approach Remove duplicates by iterating and comparing consecutive elements.
Time Complexity: O(n) Space Complexity: O(1) """ if not nums: return 0
write_idx = 0 for read_idx in range(1, len(nums)): if nums[read_idx] != nums[write_idx]: write_idx += 1 nums[write_idx] = nums[read_idx]
return write_idx + 1
# Test casesprint(removeDuplicates([1, 1, 2])) # 2, nums = [1, 2, _]print(removeDuplicates([0, 0, 1, 1, 1, 2, 2, 3, 3, 4])) # 5, nums = [0, 1, 2, 3, 4, _, _, _, _, _]#include <iostream>#include <vector>
int removeDuplicates(std::vector<int>& nums) { /* Simple Pass Approach Remove duplicates by iterating and comparing consecutive elements.
Time Complexity: O(n) Space Complexity: O(1) */ if (nums.empty()) { return 0; }
int write_idx = 0; for (int read_idx = 1; read_idx < (int)nums.size(); read_idx++) { if (nums[read_idx] != nums[write_idx]) { write_idx++; nums[write_idx] = nums[read_idx]; } }
return write_idx + 1;}
int main() { std::vector<int> nums1 = {1, 1, 2}; std::cout << removeDuplicates(nums1) << std::endl; // 2, nums = [1, 2, _]
std::vector<int> nums2 = {0, 0, 1, 1, 1, 2, 2, 3, 3, 4}; std::cout << removeDuplicates(nums2) << std::endl; // 5, nums = [0, 1, 2, 3, 4, _, _, _, _, _]
return 0;}public class RemoveDuplicatesFromSortedArraySimple { /* Simple Pass Approach Remove duplicates by iterating and comparing consecutive elements.
Time Complexity: O(n) Space Complexity: O(1) */ public static int removeDuplicates(int[] nums) { if (nums == null || nums.length == 0) { return 0; }
int writeIdx = 0; for (int readIdx = 1; readIdx < nums.length; readIdx++) { if (nums[readIdx] != nums[writeIdx]) { writeIdx++; nums[writeIdx] = nums[readIdx]; } }
return writeIdx + 1; }
public static void main(String[] args) { int[] nums1 = {1, 1, 2}; System.out.println(removeDuplicates(nums1)); // 2, nums = [1, 2, _]
int[] nums2 = {0, 0, 1, 1, 1, 2, 2, 3, 3, 4}; System.out.println(removeDuplicates(nums2)); // 5, nums = [0, 1, 2, 3, 4, _, _, _, _, _] }}/** * Simple Pass Approach * Remove duplicates by iterating and comparing consecutive elements. * * Time Complexity: O(n) * Space Complexity: O(1) * * @param {number[]} nums * @return {number} */function removeDuplicates(nums) { if (nums.length === 0) { return 0; }
let writeIdx = 0; for (let readIdx = 1; readIdx < nums.length; readIdx++) { if (nums[readIdx] !== nums[writeIdx]) { writeIdx++; nums[writeIdx] = nums[readIdx]; } }
return writeIdx + 1;}
// Test casesconsole.log(removeDuplicates([1, 1, 2])); // 2, nums = [1, 2, _]console.log(removeDuplicates([0, 0, 1, 1, 1, 2, 2, 3, 3, 4])); // 5, nums = [0, 1, 2, 3, 4, _, _, _, _, _]/*Simple Pass ApproachRemove duplicates by iterating and comparing consecutive elements.
Time Complexity: O(n)Space Complexity: O(1)*/pub fn remove_duplicates(nums: &mut Vec<i32>) -> i32 { if nums.is_empty() { return 0; }
let mut write_idx = 0; for read_idx in 1..nums.len() { if nums[read_idx] != nums[write_idx] { write_idx += 1; nums[write_idx] = nums[read_idx]; } }
(write_idx + 1) as i32}
fn main() { let mut nums1 = vec![1, 1, 2]; println!("{}", remove_duplicates(&mut nums1)); // 2, nums = [1, 2, _]
let mut nums2 = vec![0, 0, 1, 1, 1, 2, 2, 3, 3, 4]; println!("{}", remove_duplicates(&mut nums2)); // 5, nums = [0, 1, 2, 3, 4, _, _, _, _, _]}package main
import "fmt"
/*Simple Pass ApproachRemove duplicates by iterating and comparing consecutive elements.
Time Complexity: O(n)Space Complexity: O(1)*/func removeDuplicates(nums []int) int { if len(nums) == 0 { return 0 }
writeIdx := 0 for readIdx := 1; readIdx < len(nums); readIdx++ { if nums[readIdx] != nums[writeIdx] { writeIdx++ nums[writeIdx] = nums[readIdx] } }
return writeIdx + 1}
func main() { nums1 := []int{1, 1, 2} fmt.Println(removeDuplicates(nums1)) // 2, nums = [1, 2, _]
nums2 := []int{0, 0, 1, 1, 1, 2, 2, 3, 3, 4} fmt.Println(removeDuplicates(nums2)) // 5, nums = [0, 1, 2, 3, 4, _, _, _, _, _]}Approach 3: Optimized Two-Pointer
Section titled “Approach 3: Optimized Two-Pointer”A third approach demonstrating an alternative technique for solving this problem. This implementation optimizes either time or space complexity compared to the previous approaches.
Pseudocode
Section titled “Pseudocode”function approach3(): // Implementation approach goes hereSolution Code
Section titled “Solution Code”"""Solution for Remove Duplicates from Sorted Array"""
def solve(): """Implementation for approach 3 of Remove Duplicates from Sorted Array""" pass
if __name__ == "__main__": print("Solution ready")#include <bits/stdc++.h>using namespace std;
// Solution for Remove Duplicates from Sorted Array// Approach 3: Implementation
int main() {{ // Main implementation goes here return 0;}}/** * Solution for Remove Duplicates from Sorted Array * Approach 3 */public class RemoveDuplicatesFromSortedArrayOptimized {{
public static void main(String[] args) {{ // Implementation goes here }}}}/** * Solution for Remove Duplicates from Sorted Array * Approach 3 */
function solve() {{ // Implementation goes here}}
module.exports = solve;/// Solution for Remove Duplicates from Sorted Array/// Approach 3
fn main() {{ println!("Solution implementation");}}package main
import "fmt"
// Solution for Remove Duplicates from Sorted Array// Approach 3
func main() {{ fmt.Println("Solution implementation")}}