給定未排序整數數組,找出最長連續數字序列的長度(連續指數值連續,不要求數組中連續)。要求 O(n) 時間複雜度。
示例:[100, 4, 200, 1, 3, 2] → 最長序列 [1,2,3,4] 長度 4。
若對每個數嘗試向左右擴展,會導致大量重複訪問(如 1,2,3,4 各自向右擴展共訪問 10 次)。關鍵優化:
unordered_set(或 unordered_map<int, bool> 標記是否已訪問)x,只有當 x-1 不在集合中時,才以 x 為起點向右擴展(x+1, x+2, ...)此法保證總訪問次數 ≤ 2n,時間複雜度 O(n)。
class Solution {
public:
int longestConsecutive(vector& nums) {
unordered_set numSet(nums.begin(), nums.end());
int longest = 0;
for (int x : nums) {
// 只有 x 是序列起點(無 x-1)才擴展
if (numSet.count(x - 1)) continue;
int len = 1;
while (numSet.count(x + len)) ++len;
longest = max(longest, len);
}
return longest;
}
};
若要求 O(1) 額外空間(修改輸入數組),可用 unordered_map 模擬「已訪問」標記:
class Solution {
public:
int longestConsecutive(vector& num) {
unordered_map visited;
for (int x : num) visited[x] = false;
int longest = 1;
for (int x : num) {
if (visited[x]) continue; // 已處理過的序列內部元素
int len = 1;
// 向右擴展
int y = x + 1;
while (visited.count(y)) {
visited[y] = true;
++len; ++y;
}
// 向左擴展
y = x - 1;
while (visited.count(y)) {
visited[y] = true;
++len; --y;
}
longest = max(longest, len);
}
return longest;
}
};
| 技巧 | 作用 |
|---|---|
| 哈希表 O(1) 查找 | 支撐常數時間判斷數字是否存在 |
| 只從序列起點擴展 | 消除重複訪問,保證線性時間 |
| 訪問標記 | 防止同一序列被多次處理 |
| 雙向擴展 vs 單向 | 雙向需標記左右;單向(只查 x+1)代碼更簡潔 |
本題是「線性時間處理無序數組連續性問題」的教科書級範例。核心思想:用空間換時間(哈希表),用「只處理起點」消除重複工作。此模式廣泛適用於:最長連續子數組、數組中缺失的最小正整數、環形數組連續序列等變體問題。