Skip to content

Longest Consecutive Sequence

Problem Statement

Given an unsorted array of integers nums, return the length of the longest consecutive elements sequence.

You must write an algorithm that runs in O(n) time.

LeetCode: 128. Longest Consecutive Sequence

Examples

Example 1:

text
Input: nums = [100, 4, 200, 1, 3, 2]
Output: 4
Explanation: The longest consecutive elements sequence is [1, 2, 3, 4]. Therefore its length is 4.

Example 2:

text
Input: nums = [0, 3, 7, 2, 5, 8, 4, 6, 0, 1]
Output: 9
Explanation: The longest consecutive sequence is [0, 1, 2, 3, 4, 5, 6, 7, 8].

Constraints

  • 0 <= nums.length <= 10^5
  • -10^9 <= nums[i] <= 10^9

Hash Set Approach

Longest Consecutive Sequence Visualization

Key Insight

For O(n) time, use a hash set for O(1) lookups. Only start counting from sequence starts (numbers with no predecessor in the set).

Algorithm

  1. Add all numbers to a hash set
  2. For each number, check if it's a sequence start (n-1 not in set)
  3. If it's a start, count consecutive numbers (n+1, n+2, ...)
  4. Track the maximum length found

Solution

python
from typing import List

def longestConsecutive(nums: List[int]) -> int:
    """
    Find longest consecutive sequence.

    Time: O(n) - each number visited at most twice
    Space: O(n) - hash set storage
    """
    if not nums:
        return 0

    num_set = set(nums)
    max_length = 0

    for num in num_set:
        # Only start counting from sequence starts
        if num - 1 not in num_set:
            current_num = num
            current_length = 1

            # Count consecutive numbers
            while current_num + 1 in num_set:
                current_num += 1
                current_length += 1

            max_length = max(max_length, current_length)

    return max_length
java
import java.util.*;

class Solution {
    public int longestConsecutive(int[] nums) {
        Set<Integer> numSet = new HashSet<>();
        for (int num : nums) numSet.add(num);

        int maxLength = 0;

        for (int num : numSet) {
            // Only start counting from sequence starts
            if (!numSet.contains(num - 1)) {
                int currentNum = num;
                int currentLength = 1;

                while (numSet.contains(currentNum + 1)) {
                    currentNum++;
                    currentLength++;
                }

                maxLength = Math.max(maxLength, currentLength);
            }
        }

        return maxLength;
    }
}

Complexity: Time O(n) · Space O(n)

  • Time: O(n) because each number is visited at most twice - once in the outer loop and once when extending a sequence
  • Space: O(n) for storing all numbers in a hash set for O(1) lookups
python
# Alternative: Track visited numbers
def longestConsecutiveVisited(nums: List[int]) -> int:
    """
    Track visited numbers to avoid reprocessing.

    Time: O(n)
    Space: O(n)
    """
    if not nums:
        return 0

    num_set = set(nums)
    visited = set()
    max_length = 0

    for num in nums:
        if num in visited:
            continue

        length = 1
        visited.add(num)

        # Expand left
        left = num - 1
        while left in num_set:
            visited.add(left)
            length += 1
            left -= 1

        # Expand right
        right = num + 1
        while right in num_set:
            visited.add(right)
            length += 1
            right += 1

        max_length = max(max_length, length)

    return max_length

Complexity: Time O(n) · Space O(n)

  • Time: O(n) because each number is visited at most twice - once in the outer loop and once when extending a sequence
  • Space: O(n) for storing all numbers in a hash set for O(1) lookups

Why O(n) Time?

The inner while loop might seem like it could cause O(n^2), but:

  • Each number can only be the start of one sequence
  • Each number is visited at most twice (once in outer loop, once in inner)
  • Total iterations across all while loops = O(n)

Complexity Analysis

ApproachTimeSpace
Hash SetO(n)O(n)
SortingO(n log n)O(1) or O(n)
Union FindO(n * α(n)) ≈ O(n)O(n)

Sorting Approach (For Comparison)

python
def longestConsecutiveSorting(nums: List[int]) -> int:
    """
    Sort and count consecutive.

    Time: O(n log n)
    Space: O(1) if in-place sort
    """
    if not nums:
        return 0

    nums.sort()

    max_length = 1
    current_length = 1

    for i in range(1, len(nums)):
        if nums[i] == nums[i - 1]:
            # Skip duplicates
            continue
        elif nums[i] == nums[i - 1] + 1:
            current_length += 1
        else:
            max_length = max(max_length, current_length)
            current_length = 1

    return max(max_length, current_length)

Complexity: Time O(n log n) · Space O(1)

  • Time: O(n log n) dominated by the sorting step, then O(n) for the linear scan
  • Space: O(1) if sorting is done in-place, otherwise O(n) for sort buffer

Union-Find Approach

python
class UnionFind:
    def __init__(self):
        self.parent = {}
        self.size = {}

    def find(self, x):
        if x not in self.parent:
            self.parent[x] = x
            self.size[x] = 1
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]

    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        if px == py:
            return
        if self.size[px] < self.size[py]:
            px, py = py, px
        self.parent[py] = px
        self.size[px] += self.size[py]

    def get_max_size(self):
        return max(self.size.values()) if self.size else 0


def longestConsecutiveUnionFind(nums: List[int]) -> int:
    """
    Union-Find approach.

    Time: O(n * α(n)) ≈ O(n)
    Space: O(n)
    """
    if not nums:
        return 0

    uf = UnionFind()
    num_set = set(nums)

    for num in nums:
        uf.find(num)  # Initialize
        if num - 1 in num_set:
            uf.union(num, num - 1)
        if num + 1 in num_set:
            uf.union(num, num + 1)

    return uf.get_max_size()

Complexity: Time O(n) · Space O(n)

  • Time: O(n * alpha(n)) which is effectively O(n) since inverse Ackermann function alpha(n) is nearly constant
  • Space: O(n) for the Union-Find parent and size dictionaries plus the hash set

Edge Cases

  1. Empty array: [] - Return 0
  2. Single element: [5] - Return 1
  3. All same: [1,1,1] - Return 1 (duplicates don't extend sequence)
  4. Negative numbers: [-1,0,1] - Works correctly
  5. Large gaps: [1,100,200] - Three sequences of length 1

Variations

Return the Sequence

python
def longestConsecutiveSequence(nums: List[int]) -> List[int]:
    """Return the actual longest consecutive sequence."""
    if not nums:
        return []

    num_set = set(nums)
    max_length = 0
    best_start = None

    for num in num_set:
        if num - 1 not in num_set:
            current_num = num
            current_length = 1

            while current_num + 1 in num_set:
                current_num += 1
                current_length += 1

            if current_length > max_length:
                max_length = current_length
                best_start = num

    if best_start is None:
        return []

    return list(range(best_start, best_start + max_length))

Count All Consecutive Sequences

python
def countConsecutiveSequences(nums: List[int], min_length: int = 1) -> int:
    """Count number of consecutive sequences of at least min_length."""
    if not nums:
        return 0

    num_set = set(nums)
    count = 0

    for num in num_set:
        if num - 1 not in num_set:
            length = 1
            while num + length in num_set:
                length += 1
            if length >= min_length:
                count += 1

    return count

Longest Consecutive Sequence in Matrix

python
def longestConsecutiveMatrix(matrix: List[List[int]]) -> int:
    """
    Find longest consecutive sequence where consecutive
    numbers are adjacent (4-directionally).
    """
    if not matrix or not matrix[0]:
        return 0

    m, n = len(matrix), len(matrix[0])
    memo = {}

    def dfs(i, j, prev_val):
        if i < 0 or i >= m or j < 0 or j >= n:
            return 0
        if matrix[i][j] != prev_val + 1:
            return 0
        if (i, j) in memo:
            return memo[(i, j)]

        result = 1 + max(
            dfs(i+1, j, matrix[i][j]),
            dfs(i-1, j, matrix[i][j]),
            dfs(i, j+1, matrix[i][j]),
            dfs(i, j-1, matrix[i][j])
        )
        memo[(i, j)] = result
        return result

    max_len = 0
    for i in range(m):
        for j in range(n):
            # Check if this could be a sequence start
            val = matrix[i][j]
            is_start = True
            for di, dj in [(0,1),(0,-1),(1,0),(-1,0)]:
                ni, nj = i + di, j + dj
                if 0 <= ni < m and 0 <= nj < n and matrix[ni][nj] == val - 1:
                    is_start = False
                    break
            if is_start:
                max_len = max(max_len, 1 + max(
                    dfs(i+1, j, val),
                    dfs(i-1, j, val),
                    dfs(i, j+1, val),
                    dfs(i, j-1, val)
                ))

    return max_len
Binary Tree Longest Consecutive Sequence (LeetCode 298)

Problem: Find longest consecutive sequence path in binary tree (parent to child only).

Key Insight: DFS tracking current sequence length. Reset or extend at each node.

Approach: Pass expected value to children. If child matches, extend count; otherwise restart.

Complexity: Time O(n), Space O(h)

Binary Tree Longest Consecutive Sequence II (LeetCode 549)

Problem: Find longest consecutive sequence path that can go child-parent-child.

Key Insight: Track both increasing and decreasing paths from each node.

Approach: DFS returning (increasing_length, decreasing_length). Combine across root.

Complexity: Time O(n), Space O(h)

Longest Continuous Increasing Subsequence (LeetCode 674)

Problem: Find length of longest contiguous strictly increasing subarray.

Key Insight: Simple linear scan, reset count when sequence breaks.

Approach: Track current length, reset to 1 when current <= previous. Track max seen.

Complexity: Time O(n), Space O(1)

Maximum Consecutive Floors Without Special Floors (LeetCode 2274)

Problem: Find maximum number of consecutive floors without special floors.

Key Insight: Sort special floors, find max gap between consecutive special floors.

Approach: Sort special array. Max gap is max(special[i] - special[i-1] - 1) plus boundaries.

Complexity: Time O(n log n), Space O(1)