返回最后一个重复元素的值:从数组末尾反向遍历,用unordered_set记录已见元素,首次遇到已在集合中的元素即返回;空数组或无重复时抛异常;时间O(n),空间O(n)。

用反向遍历 + std::unordered_set 记录已见元素
直接从数组末尾往前扫,遇到第一个「之前已经出现过」的元素就返回——这是最直观且高效的做法。关键不是“找重复”,而是“找最后一个位置上、其值在更靠后位置已出现过”的元素。
注意:std::unordered_set 只负责记录「从右往左过程中,已经见过哪些值」,不关心索引或次数。一旦当前元素在集合中存在,说明它在右侧至少出现过一次,即为所求。
- 时间复杂度
O(n),空间O(n)(最坏情况所有元素不同) - 不要用
std::set:没必要排序,徒增O(log n)开销 - 若数组为空或全无重复,需提前判断并返回特定值(如
std::nullopt或抛异常)
int findLastDuplicate(const std::vector<int>& arr) {
std::unordered_set<int> seen;
for (int i = arr.size() - 1; i >= 0; --i) {
if (seen.find(arr[i]) != seen.end()) {
return arr[i];
}
seen.insert(arr[i]);
}
throw std::runtime_error("no duplicate found");
}当需要返回下标而非元素值时,改用 std::unordered_map
如果需求是“最后一个重复元素的最后一次出现位置”,或者要区分「首次出现」和「末次出现」,就得记下每个值的最新下标。此时 std::unordered_map<int, int> 更合适:键是元素值,值是它最近一次出现的索引。
- 正向遍历一次,更新每个值的最新位置
- 再反向遍历,对每个元素查 map 中是否存有更靠后的索引(即
map[val] > current_index) - 第一个满足条件的
current_index对应的arr[current_index]就是答案 - 避免误判单次出现元素:必须确保该值在 map 中记录的位置 ≠ 当前位置
手写循环比 std::find_first_of 或 std::count 更可靠
别试图用标准算法组合解决这个问题。例如:std::count 每次都重扫整个数组,O(n²);std::find_first_of 是查找子序列,语义不匹配;std::adjacent_find 只处理相邻重复。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
立即学习“C++免费学习笔记(深入)”;
- 没有现成 STL 算法能表达「某个值在当前位置右侧是否出现过」这个逻辑
- 强行套用会使代码变长、可读性下降,且无法提前退出
- 手动反向循环 + 哈希集合,逻辑直白,编译器也容易优化
注意有符号/无符号整数混用导致的循环失效
常见坑:for (size_t i = arr.size() - 1; i >= 0; --i) 在 arr 为空时,arr.size() - 1 会变成极大正数(size_t 下溢),导致无限循环或越界访问。
- 务必把循环变量声明为有符号类型(如
int i),或先判空 - 更安全写法:
if (arr.empty()) return ...; for (int i = static_cast<int>(arr.size()) - 1; i >= 0; --i) - Clang/GCC 加
-Wsign-conversion能捕获这类隐式转换警告
C++ 里“最后一个重复元素”本质是位置敏感问题,核心动作永远是「从右往左查,配合哈希结构快速判定右侧可见性」。边界检查和类型安全比算法花样更重要。

















