Coding Challenge: Remove and Rearrange Array Elements In-Place in O(1) Memory and O(n) Time
Lately I've been trying to challenge myself by taking a stab at some common coding questions asked in software engineering job interviews. After years of working on apps you would think that this kind of thing comes easy, but software development in the modern age comes with a heavy side of Googling and lookup, so challenging your brain in this way to implement an algorithm or process from just its definition or description is good practice to keep you sharp.
Yesterday, I came across a question on LeetCode that was asking me to remove all elements of an array that match a certain value. Pretty simple right?
Wrong. There is a catch which means this above solution cannot be used. We are required to perform the removal in constant O(1)
memory, so we can't create
any new arrays, or modify the existing array. We are asked to do it in O(n)
time as well. So we need to modify the array in place, while looping over its length
max one time. Here's how I did it.
The exact working of the question looks like this:
So we need to rearrange the elements of the input array by moving all unwanted values to the right side of it, then returning the length of the new array, which can be in any order. Seems like the best way to accomplish this is to iterate over the length of the array, swapping elements if they are a match with one on the right side, and keep track of the right edge of the array we will return. In code, this looks like:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# @param {Integer[]} nums
# @param {Integer} val
# @return {Integer}
def remove_element(nums, val)
right = nums.length-1
i = right
while i >= 0
if nums[i] == val
# swap the element with whatever is on the right.
nums[i] = nums[right]
nums[right] = val
right -= 1
end
i -= 1
end
return right + 1
end
Let's go over this line-by-line.
- Line 6: We need to keep track of the right edge index of the array we will use for the return value, i.e. the last index, hence
right
. This also indicates where we need to swap items with if we should come across a match with any other element. As we come across matches, we will decrement this boundary. - Line 7: Setup an initial array index value
i
that keeps track of where we are in the array iteration. We are starting on the right side of the array and counting down, soi
is initialized asright
- Line 8: Loop
i
over the length of the array, decrementing until we hit the first index. - Line 9: Check to see if the number in the array at index
i
is the one we are looking for,val
- Line 11: It matched, so we need to move some things around. The value at index
i
isval
, so we can immediately overwrite it with whatever the last value is of our "included" array, which is conveniently indicated by ourright
index. - Line 12: Though it technically isn't asked of us, it bothered me that the returned array did not contain the same elements as before the method, so I wanted to move this matching value back outside the index of our "included" array and into a "removed" section, to the right of
right
. - Line 13: We've added a new element to the "removed" section, and the "included" section's length shortened by 1, so let's decrement the
right
index to keep track of that. - Line 15: Regardless of whether or not we found a match, we need to move on to the next index down the array, so let's decrement
i
to do that. - Line 18: Finally, return the number of elements in the new array. Because
right
was a zero-based index value, we need to add 1 to it to get the number of elements up to that index.
Submitting this code to LeetCode passess all of their tests, and has the following stats:
Onward to the next problem!
Was this page helpful for you? Buy me a slice of 🍕 to say thanks!
Comments