在使用eraseApi的时候需要注意的事情

25 阅读2分钟

在写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,否则就会跳过一个元素。