保留元素顺序的vector去重函数存在逻辑错误,求分析与实现思路
现有函数的逻辑错误
你的代码存在3个核心问题,导致仅相邻重复场景能生效:
- 内层循环遍历逻辑错误:你的需求是保留元素第一次出现的顺序,也就是后续出现的、已经在前面出现过的元素要全部删除。但你内层循环固定从下标1开始遍历,当外层循环
i走到靠后的下标时,不会对比i位置的元素是否已经在0~i-1区间出现过,反而会直接把i位置的元素当成要保留的基准,去删除后续的重复项,这就会导致前面已经出现过的元素在后面再次出现时被保留,比如你示例输出里重复的1就是这个原因导致的。 - 删除元素后未处理下标偏移:调用
erase删除x位置的元素后,原本x+1位置的元素会自动挪到x位置,此时你的代码直接执行x++会直接跳过这个新移动到x位置的元素,导致漏检部分重复项。 - 外层循环边界动态变化但未适配:
erase会缩小vector的长度,你外层循环的终止条件inputVector.size() - 1是动态变化的,极端场景下会出现下标越界的隐患。
手动实现的底层思路
我们的目标是:仅保留每个元素第一次出现的位置,后续重复元素全部删除,这里提供两种常用实现思路:
方案1:原地修改(O(n²)时间,O(1)额外空间)
适合内存紧张的场景,不需要额外申请存储结构,逻辑如下:
- 维护一个
valid_idx变量表示当前已去重的有效区域的最后下标,初始值为0,0~valid_idx区间的元素都是已经完成去重、无重复的元素。 - 从下标1开始遍历整个vector的每个元素:
- 检查当前元素是否在
0~valid_idx区间内出现过 - 如果没有出现过,就把
valid_idx加1,将当前元素赋值到valid_idx的位置 - 如果已经出现过,直接跳过当前元素
- 检查当前元素是否在
- 遍历完成后,将vector从
valid_idx + 1到末尾的所有元素全部删除即可。
对应代码实现:
void vectorDeduplicator(std::vector<std::string>& inputVector){ // 空vector直接返回 if(inputVector.empty()) return; int valid_idx = 0; // 从第二个元素开始遍历 for(int i = 1; i < inputVector.size(); i++){ bool is_duplicate = false; // 检查当前元素是否在已去重区间出现过 for(int j = 0; j <= valid_idx; j++){ if(inputVector[i] == inputVector[j]){ is_duplicate = true; break; } } if(!is_duplicate){ valid_idx++; inputVector[valid_idx] = inputVector[i]; } } // 截断后面的无效元素 inputVector.erase(inputVector.begin() + valid_idx + 1, inputVector.end()); }
方案2:空间换时间(O(n)时间,O(k)额外空间,k为去重后元素数量)
适合对性能要求高的场景,用额外的存储结构记录已经出现过的元素,避免内层循环比对:
- 维护一个
valid_idx变量表示当前已去重的有效区域的最后下标,初始值为0,同时用一个哈希集合记录已经出现过的元素。 - 遍历整个vector的每个元素:
- 如果当前元素不在哈希集合中,就将它加入集合,赋值到
valid_idx位置,然后valid_idx加1 - 如果已经在集合中,直接跳过
- 如果当前元素不在哈希集合中,就将它加入集合,赋值到
- 遍历完成后,将vector从
valid_idx到末尾的所有元素全部删除即可。
对应代码实现:
#include <unordered_set> void vectorDeduplicator(std::vector<std::string>& inputVector){ std::unordered_set<std::string> seen; int valid_idx = 0; for(int i = 0; i < inputVector.size(); i++){ if(seen.find(inputVector[i]) == seen.end()){ seen.insert(inputVector[i]); inputVector[valid_idx] = inputVector[i]; valid_idx++; } } inputVector.erase(inputVector.begin() + valid_idx, inputVector.end()); }
两种方案都可以正确处理你给出的测试用例,输入1 1 2 2 4 4 3 3 1 1 3 3 3 2 2时,输出为[1,2,4,3],符合保留首次出现顺序去重的要求。
内容的提问来源于stack exchange,提问作者ool123
相关产品推荐
相关产品推荐

