在写leetcode的时候,一道比较简单的题目,题目是这样的
给你一个数组 nums
**和一个值 val
,你需要 原地 移除所有数值等于 val
**的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1)
额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
简单来说就是删除指定元素,在调用eraseApi的时候,出现了下面的错误
================================================================= ==20==ERROR: AddressSanitizer: negative-size-param: (size=-8) #5 0x7f76ea8cf082 (/lib/x86_64-linux-gnu/libc.so.6+0x24082) 0x6020000000a0 is located 0 bytes to the right of 16-byte region [0x602000000090,0x6020000000a0) allocated by thread T0 here: #6 0x7f76ea8cf082 (/lib/x86_64-linux-gnu/libc.so.6+0x24082) ==20==ABORTING
其中的原因是这段代码使用了vector
容器的erase
函数来删除元素,这会导致后续元素的位置向前移动,可能会影响到循环的正确执行。
public:
int removeElement(vector<int>& nums, int val) {
int lengrh=nums.size();
for(int i=0;i<lengrh;i++){
if(nums[i]==val){
nums.erase(nums.begin()+i);
}
}
return nums.size();
}
};
改进之后,如下
public:
int removeElement(vector<int>& nums, int val) {
int length = nums.size();
int i = 0;
while (i < length) {
if (nums[i] == val) {
nums.erase(nums.begin() + i); // 删除当前位置的元素
length--; // 更新数组长度
} else {
i++; // 只有在元素不等于目标值时才增加索引
}
}
return nums.size();
}
};
这段代码中,我们使用了一个while
循环来替代原来的for
循环,并且在删除元素时没有直接增加索引i
,而是只有在元素不等于目标值时才增加索引。这样可以确保每次删除元素后,都会正确地移动到下一个位置。
究其原因是:
erase
函数会将指定位置的元素从容器中删除,并且将后面的元素向前移动,以填补空缺。这样就会导致后续循环的正确性受到影响。
例如,在一个数组中删除第i个元素时,后面的元素都会向前移动一个位置,所以原来在第i+1个位置的元素现在会被移动到第i个位置,而原来在第i+2个位置的元素现在会被移动到第i+1个位置,以此类推。如果在循环中使用了索引i,那么在删除元素后,i的值应该减1,否则就会跳过一个元素。