Remove Element — LeetCode #27 (Easy)
Tags: Array, Two Pointers
Related patterns: Hash Map, Array, Two Pointers
Brute Force approach
Time complexity: O(n²). Space complexity: O(1).
The brute force approach involves creating a new array and copying over all elements that are not equal to the specified value. This is straightforward but inefficient as it requires extra space and multiple passes through the array.
The time complexity is O(n²) because we are iterating through the array and for each element, we may be copying it to a new array, which can take linear time. The space complexity is O(1) since we are using a fixed amount of extra space.
- Step 1: Initialize a new array to hold the elements that are not equal to val.
- Step 2: Iterate through the original array and for each element, check if it is not equal to val.
- Step 3: If the element is not equal to val, add it to the new array.
- Step 4: Finally, return the length of the new array.
Let's dry-run the first example: nums = [3, 2, 2, 3], val = 3.
1. Initialize new_nums as an empty array: new_nums = [].
2. Iterate through nums:
- For num = 3, it's equal to val, so skip it.
- For num = 2, it's not equal to val, add it to new_nums: new_nums = [2].
- For num = 2, it's not equal to val, add it to new_nums: new_nums = [2, 2].
- For num = 3, it's equal to val, so skip it.
3. Now, new_nums = [2, 2]. Modify nums: nums[:2] = [2, 2].
4. Return length of new_nums, which is 2.
Optimal Solution (Two Pointers) approach
Time complexity: O(n). Space complexity: O(1).
The optimal approach uses the two pointers technique to efficiently remove elements in-place. One pointer traverses the array while the other keeps track of the position to place the next valid element.
The time complexity is O(n) because we make a single pass through the array, and the space complexity is O(1) since we are modifying the array in place without using additional storage.
- Step 1: Initialize a pointer 'k' to 0, which will track the position of the next valid element.
- Step 2: Iterate through the array with another pointer 'i'.
- Step 3: If nums[i] is not equal to val, assign nums[k] = nums[i] and increment k.
- Step 4: After the loop, k will be the count of elements not equal to val.
Let's dry-run the first example: nums = [3, 2, 2, 3], val = 3.
1. Initialize k = 0.
2. Iterate through nums:
- For i = 0, nums[0] = 3 (equal to val), skip it.
- For i = 1, nums[1] = 2 (not equal to val), set nums[k] = nums[1] (nums[0] = 2), increment k to 1.
- For i = 2, nums[2] = 2 (not equal to val), set nums[k] = nums[2] (nums[1] = 2), increment k to 2.
- For i = 3, nums[3] = 3 (equal to val), skip it.
3. The final array is [2, 2, _, _] and k = 2.
Key Insights
- Using the two pointers technique allows us to efficiently modify the array in-place without needing extra space.
- Understanding that we can overwrite elements in the original array rather than removing them can simplify the problem.
Common Mistakes
- Students often try to create a new array instead of modifying the original array in-place, leading to unnecessary space usage.
- Another common mistake is not properly managing the index of the valid elements, which can lead to incorrect counts.
Interview Tips
- When you first see this problem, clarify that you understand it requires in-place modification and that the order of elements can change.
- Communicate your approach clearly, mentioning that you plan to use the two pointers technique to track valid elements.
- Be sure to mention edge cases, such as when the array is empty or when all elements are equal to val.