**标签**：`数组` `哈希表`
 0
## 题目理解

- **输入**：一个未排序的整数数组 `nums`，可能包含重复值，长度可以为 0。
- **输出**：最长连续序列的长度。这里的“连续序列”指的是数值连续（如 1,2,3,4），**不要求元素在原数组中的位置连续**，只需要这些数值都存在即可。
- **要求**：算法时间复杂度 O(n)。
- **例子**：`nums = [100,4,200,1,3,2]`，最长连续序列是 `[1,2,3,4]`，长度为 4。
- **注意**：重复的数字不会增加长度（例如 `[1,0,1,2]` 中，1 出现了两次，但最长连续序列是 `[0,1,2]`，长度 3）。

---

## 解法一：排序 + 遍历（简单但不符合 O(n) 要求）

> 这是最容易想到的方法：先排序，然后遍历一次，统计连续递增的段长度。因为要求 O(n)，排序的 O(n log n) 并不满足，但很适合零基础理解题意。

### 思路

1. 如果数组为空，直接返回 0。
2. 对数组进行排序（升序）。
3. 遍历排序后的数组，用一个变量 `current_len` 记录当前连续序列的长度，一个变量 `max_len` 记录遇到的最长长度。
4. 遍历时比较当前元素和前一个元素：
   - 如果当前元素 == 前一个元素，重复值跳过（不影响连续序列）。
   - 如果当前元素 == 前一个元素 + 1，说明连续，`current_len` 加 1。
   - 否则，连续中断，更新 `max_len`，`current_len` 重置为 1。
5. 遍历结束后，再更新一次 `max_len`。
6. 返回 `max_len`。

### 代码

```python
class Solution:
    def longestConsecutive(self, nums: list[int]) -> int:
        # 处理空数组
        if not nums:
            return 0

        # 排序
        nums.sort()   # 原地排序，时间复杂度 O(n log n)

        max_len = 1        # 最长序列长度
        current_len = 1    # 当前连续序列长度

        # 从第二个元素开始遍历
        for i in range(1, len(nums)):
            # 如果当前值和前一个值相同，跳过（不重复计数）
            if nums[i] == nums[i-1]:
                continue
            # 检查是否连续
            if nums[i] == nums[i-1] + 1:
                current_len += 1
            else:
                # 连续中断，更新最大值并重置当前长度
                if current_len > max_len:
                    max_len = current_len
                current_len = 1

        # 循环结束后，最后一段连续序列也需要比较
        if current_len > max_len:
            max_len = current_len

        return max_len

# 测试
sol = Solution()
print(sol.longestConsecutive([100,4,200,1,3,2]))  # 输出 4
print(sol.longestConsecutive([0,3,7,2,5,8,4,6,0,1]))  # 输出 9
print(sol.longestConsecutive([1,0,1,2]))  # 输出 3
print(sol.longestConsecutive([]))  # 输出 0
```

### 复杂度分析

| 维度 | 复杂度 | 说明 |
|------|--------|------|
| 时间 | O(n log n) | 排序占用主要时间，无法达到题目要求的 O(n) |
| 空间 | O(1) 或 O(n) | 排序可能占用额外空间（取决于 Python 的 Timsort），通常视为 O(n) |

### 边界情况

- 空数组：直接返回 0。
- 所有元素相同：如 `[1,1,1]`，排序后连续判断中重复值被跳过，`current_len` 始终保持 1，最后返回 1。
- 只有一个元素：返回 1。
- 负数存在：排序和加减都能正确处理。

---

## 解法二：哈希集合（O(n) 最优解法）

> 要满足 O(n) 时间，就不能排序。核心思路：**只对每个连续序列的“起点”元素进行查找**。利用哈希集合可以 O(1) 判断一个数是否存在。

### 思路

1. 将数组中的所有元素放入一个哈希集合（`set`），自动去重。
2. 初始化 `max_len = 0`。
3. 遍历集合中的每个元素 `num`：
   - 判断 `num - 1` 是否在集合中。
   - **如果 `num - 1` 不存在**，说明 `num` 是一个连续序列的起点（最小的那个数）。
   - 从起点开始，不断检查 `num+1`, `num+2`, … 是否在集合中，并计数长度。
   - 记录这个序列的长度，更新 `max_len`。
   - 如果 `num - 1` 存在，说明 `num` 不是起点，跳过（因为从更小的起点出发时已经统计过这个序列了）。
4. 返回 `max_len`。

为什么这样是 O(n) 的？因为每个元素最多被访问两次：一次作为潜在起点，另一次在从起点向后延伸的过程中被检查。Python 的集合 `in` 操作平均 O(1)。

### 代码

```python
class Solution:
    def longestConsecutive(self, nums: list[int]) -> int:
        # 用集合去重，同时提供 O(1) 的成员查询
        num_set = set(nums)
        max_len = 0

        # 遍历集合中的每个数
        for num in num_set:
            # 只有当 num-1 不在集合中时，num 才是一个连续序列的起点
            if num - 1 not in num_set:
                # 从 num 开始向后尝试延伸
                current_num = num
                current_len = 1

                # 不断检查 current_num + 1 是否存在
                while current_num + 1 in num_set:
                    current_num += 1
                    current_len += 1

                # 更新最长长度
                if current_len > max_len:
                    max_len = current_len

        return max_len

# 测试
sol = Solution()
print(sol.longestConsecutive([100,4,200,1,3,2]))  # 输出 4
print(sol.longestConsecutive([0,3,7,2,5,8,4,6,0,1]))  # 输出 9
print(sol.longestConsecutive([1,0,1,2]))  # 输出 3
print(sol.longestConsecutive([]))  # 输出 0
```

### 复杂度分析

| 维度 | 复杂度 | 说明 |
|------|--------|------|
| 时间 | O(n) | 每个元素最多作为起点一次，且 while 循环中每个元素只会被访问一次（被从起点出发延伸时） |
| 空间 | O(n) | 哈希集合存储所有不重复元素 |

### 边界情况

- 空数组：集合为空，`max_len` 保持 0，正确返回。
- 重复元素：集合自动去重，不影响结果（例如 `[1,1,2]` 只会处理一次 1, 2）。
- 全部元素不连续：每个数都是起点，每个数单独序列长度为 1，最后返回 1。
- 负数：负数值也能正常判断 `-1` 是否在集合中，例如 `[-1,0,1]`。

---

## 解法对比总结

| 解法 | 时间复杂度 | 空间复杂度 | 推荐场景 |
|------|-----------|-----------|----------|
| 解法一：排序 + 遍历 | O(n log n) | O(1) / O(n) | 快速验证思路，数据量小且不要求严格 O(n) |
| 解法二：哈希集合 | O(n) | O(n) | 面试必写，满足题目进阶要求，时间复杂度最优 |

- **零基础建议**：先理解排序解法，明白“连续”的含义以及如何处理重复值。再学习哈希集合解法，理解“只从起点开始查找”能避免重复统计。
- **面试要点**：必须能写出 O(n) 的解，并解释为什么每个元素只被访问有限次。同时注意处理空数组。