128. 最长连续序列

128. 最长连续序列 - 力扣(LeetCode)

class Solution {
public:
  int longestConsecutive(vector<int>& nums) {
    int Longest = 0;
    // So straightforward... Putting the whole vector into set is for both
    // deduplication and O(1) search, which is very important.
    unordered_set<int> Set(nums.begin(), nums.end());

    for (int X : Set) {
      // Do not search in the middle of consecutive sequences. This reduces a
      // lot of time consumption.
      if (Set.count(X - 1))
        continue;

      int ThisLength = 1;
      // O(1) instead of O(n) search! We can just count from X + 1 instead of X
      // since we have already counted X in the outer for-loop.
      while (Set.count(X + 1)) {
        ++X;
        ++ThisLength;
      }
      Longest = max(ThisLength, Longest);
    }
    return Longest;
  }
};

这个解决方案有点太简单粗暴了,但是确实有用,因为乱序数组的查找操作时间复杂度是 \(\mathrm O(n)\),而转换为 unordered_set 可以将查找操作变为 \(\mathrm O(1)\),再加上不从中间位置开始搜索的分支处理,整体的复杂度确实就是 \(\mathrm O(n\times1)=\mathrm O(n)\)。

二刷

class Solution {
public:
  int longestConsecutive(vector<int>& nums) {
    int Result = 0;
    unordered_set<int> Set(nums.begin(), nums.end());

    for (int X : Set) {
      // Just don't cut the rope at the middle. We need it whole.
      if (Set.contains(X + 1))
        continue;

      // The outer loop is just for the X.
      int Length = 1;
      while (Set.contains(X - 1)) {
        // Lengthen the rope.
        ++Length;
        --X;
      }

      Result = max(Result, Length);
    }
    return Result;
  }
};

我靠,这个我真的没想起来。而且说实话这个思路好像写起来也不是那么符合直觉。但是如果有analogy的话就好一点,比如

Pasted image 20260912111652.png

可以明显地看到我们为什么要忽略有\(X+1\)的情况,以及为什么int Length = 1;放在循环里面——因为外循环只是用来找起始点的,移动\(X\)计数是内循环干的事情,那么找到起始点之后自然就至少有了1的长度。