滑动窗口求最长无重复子串的核心是用左右指针维护窗口,unordered_set版需循环移左指针直至重复字符被移出,unordered_map版可直接跳转但left须取max(left, map[c]+1),二者均需覆盖空串等边界情况。

滑动窗口用 std::unordered_set 维护字符是否重复最直接
核心思路是用左右指针维护一个窗口,右指针扩张时检查新字符是否已在窗口内出现;若已存在,就移动左指针直到该字符被移出。用 std::unordered_set 存当前窗口内所有字符,插入失败即说明重复。
常见错误是左指针只挪一次就继续右扩,导致漏掉中间重复字符——必须循环移动左指针,直到被重复的字符彻底移出集合。
- 每次
set.insert(c)返回std::pair<iterator bool></iterator>,看.second判断是否插入成功 - 左指针移动时,要同步调用
set.erase(s[left]),不能只改索引 - 长度更新必须在确认当前窗口合法后(即插入成功后)再计算:
max_len = std::max(max_len, right - left + 1)
std::unordered_map 记录位置能省去左指针逐个试探
当字符重复时,如果知道它上一次出现的位置,就能直接把左指针跳到那个位置+1,避免一步步挪。这时用 std::unordered_map<char int></char> 存每个字符最近一次出现的下标。
关键点在于:左指针不能往回退。比如 "abba" 中,第二次遇到 'a' 时,上次位置是 0,但此时 left 已经移到 2(因为中间被 'b' 推过),所以更新 left 要取 std::max(left, map[c] + 1)。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
立即学习“C++免费学习笔记(深入)”;
- 初始化
left = 0,遍历right从 0 到s.size()-1 - 若
map.find(c) != map.end(),则left = std::max(left, map[c] + 1) - 无论是否重复,都要更新
map[c] = right - 长度更新仍为
right - left + 1,别漏掉
边界情况和性能差异要注意
空字符串、单字符、全重复(如 "aaaa")、全不重复(如 "abcde")这四类必须手动验证一遍。用 std::unordered_set 版本在极端重复场景下可能退化成 O(n²),因为左指针要反复挪;而 map 版本稳定 O(n),但多一次哈希写入开销。
- 字符串为空时,
s.size()是 0,循环不进,直接返回 0 —— 不用特判,但调试时容易忽略 - 字符集不是 ASCII?
char作map键没问题,C++ 中char可隐式转整型,但注意有符号性:若用unsigned char更稳妥 - 不要用
std::set替代unordered_set,红黑树查找是 O(log n),没必要
实际写的时候,map 版本更常用也更健壮。最容易被忽略的是左指针的“不可逆”特性——它只能右移,不能因为某次重复就盲目设成 map[c] + 1 而不和当前 left 取大。

















