直接排序再遍历会出错,因破坏原始索引且重复元素导致误判连续长度;正确做法是用unordered_set去重后,仅当num-1不存在时以num为起点扩展,确保O(n)时间复杂度。

为什么直接排序再遍历会出错
排序后遍历看似简单,但会破坏原始索引关系,而题目只要求“值连续”,不关心位置。更关键的是:如果数组含重复数(比如 [1,2,2,3]),排序后相邻判断会把重复值误判为连续,导致长度算成 4 而不是 3。必须先去重,再按值排序,否则 std::unique 不处理原地重复逻辑,容易漏掉边界 case。
用 unordered_set 去重 + 首位判定是关键
核心思路是:对每个数,只在它是某连续序列的起点时才开始扩展。怎么判断起点?看 x-1 是否不在集合中。这样每个序列只被访问一次,时间复杂度稳定 O(n)。
- 先将所有数插入
std::unordered_set<int></int>,自动去重 - 遍历集合中每个元素
num,检查num - 1是否存在;不存在,说明num是起点 - 从
num开始,用 while 循环检查num + 1、num + 2…是否在集合中,计数 - 更新全局最大长度
示例:[100,4,200,1,3,2] → set 为 {1,2,3,4,100,200};只有 1 和 100 满足 x-1 不存在,分别延伸得长度 4 和 1。
注意 int 溢出和空输入边界
当数组为空或只有一个元素时,直接返回对应长度即可。更隐蔽的问题是:若数组含 INT_MIN,检查 num - 1 会溢出。安全做法是把条件写成 !numSet.count(num - 1LL)(用 long long 避免溢出),或者改用 numSet.find(num - 1) == numSet.end() —— 后者不触发算术运算,更稳妥。
立即学习“C++免费学习笔记(深入)”;
- 空数组:返回 0
- 单元素:返回 1
- 含
INT_MIN:避免直接计算num - 1,优先用find判不存在
别用 map 存数值频率来模拟 set
有人用 std::map<int int></int> 存频次,再遍历 key,这不仅多占内存,而且 map 的遍历是 O(n log n),破坏了算法本意的线性性能。哪怕只读 key,底层仍是红黑树有序遍历。必须用 unordered_set,且不要调用 begin()/end() 遍历 map 或 set 的 iterator —— 直接 range-based for 遍历 set 即可。
真正影响性能的不是容器选择,而是是否让每个数字最多被访问两次:一次进集合,一次作为起点扩展。任何引入排序、嵌套循环或 map 遍历的操作,都会让最坏复杂度退化。


















