I noticed a particular timing behaviour while solving LeetCode problem 27. Remove Element:
Given an integer array
nums
and an integerval
, remove all occurrences ofval
innums
in-place. The order of the elements may be changed. Then return the number of elements innums
which are not equal toval
.Consider the number of elements in
nums
which are not equal toval
bek
, to get accepted, you need to do the following things:
- Change the array
nums
such that the firstk
elements ofnums
contain the elements which are not equal toval
. The remaining elements ofnums
are not important as well as the size ofnums
.- Return
k
.
When I submitted the code below, I got a time-out:
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int count=0;
for(int i=0;i<nums.size();i++){
if(nums[i]==val){
for(int j=i;j+1<nums.size();j++){
nums[j]=nums[j+1];
count+=1;
}
i--;
}
}
return nums.size()-count;
}
};
Then I tried to use a variable to record the value of nums.size()
and use it as the loop condition. This time the code finished within the alotted time.
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int count=0,size=nums.size();
for(int i=0;i<size;i++){
if(nums[i]==val){
for(int j=i;j+1<size;j++){
nums[j]=nums[j+1];
count+=1;
}
i--;
size--;
}
}
return size;
}
};
I don't understand why this could be such an important difference.
I would like to know the time that .size()
uses and its internal code, with its time complexity.
Calling nums.size()
on each iteration or storing it in a variable first does not actually make much of a difference. The real issue is that you run into an infinite loop when the last element is the value to remove, as you keep attempting to shift the remaining elements (of which there are none) down over and over. In the second version of your code, you decrement the size when shifting, which precludes going into the section of the vector
that contains useless elements not part of the solution.
On another note, since the question states that the size of nums
after the method executes doesn't matter, you can directly delete the matching elements from the vector. This can be easily done in one line with std::erase
(which has linear time complexity).
int removeElement(vector<int>& nums, int val) {
std::erase(nums, val);
return nums.size();
}