12. Longest Consecutive Sequence
π LeetCode Problem: 128. Longest Consecutive Sequence
π Difficulty: Medium
π·οΈ Topics: Array, Hash Table, Union Find
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.
Example 1:
Input: nums = [100,4,200,1,3,2]
Output: 4
Explanation: The longest consecutive sequence is [1, 2, 3, 4]. Therefore its length is 4.
Example 2:
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
π¨ Visual Understanding
The Problem Visualized
Input: [100, 4, 200, 1, 3, 2]
Unsorted array:
[100, 4, 200, 1, 3, 2]
If we sort them:
[1, 2, 3, 4, 100, 200]
ββconsecutiveββ
Consecutive sequences:
- [1, 2, 3, 4] β length 4 β (longest)
- [100] β length 1
- [200] β length 1
Result: 4
What is a Consecutive Sequence?
Consecutive = Numbers differ by exactly 1
Examples:
[1, 2, 3, 4] β Consecutive (1β2β3β4)
[1, 3, 5, 7] β Not consecutive (gaps of 2)
[5, 4, 3, 2] β Can be reordered: [2, 3, 4, 5]
[1, 2, 2, 3] β Duplicates ignored: [1, 2, 3]
Key insight: Order in array doesn't matter!
We just need to find which numbers form sequences.
Approach Comparison
Approach 1: Sorting
[100, 4, 200, 1, 3, 2]
β Sort
[1, 2, 3, 4, 100, 200]
Then scan for consecutive runs
Time: O(n log n) - sorting
β Violates O(n) requirement
Approach 2: HashSet (Optimal)
Convert to set: {100, 4, 200, 1, 3, 2}
For each number, check if it's a sequence start:
- If (num-1) NOT in set β this is a start!
- Count how far sequence goes: num+1, num+2, ...
1: is 0 in set? No β START! Count: 1,2,3,4 β length 4
2: is 1 in set? Yes β NOT a start (skip)
3: is 2 in set? Yes β NOT a start (skip)
4: is 3 in set? Yes β NOT a start (skip)
100: is 99 in set? No β START! Count: 100 β length 1
200: is 199 in set? No β START! Count: 200 β length 1
Max length: 4 β
Time: O(n) - each number visited at most twice
π― Approach 1: Sorting
The Most Natural Thinking π
Core Logic:
Sort the array, then scan for consecutive sequences:
1. Sort array
2. Scan from left to right
3. Track current sequence length
4. If current number = previous number + 1 β extend sequence
5. If current number = previous number β skip duplicate
6. Otherwise β start new sequence
7. Keep track of maximum length
Why This Works: - Sorting brings consecutive numbers together - Easy to identify sequences with single scan - Simple to implement
Why This Fails Requirements: - Sorting is O(n log n) - Problem requires O(n) time - Good for understanding, not for submission
Implementation
public int longestConsecutive(int[] nums) {
if (nums.length == 0) return 0;
// Sort the array
Arrays.sort(nums);
int maxLength = 1;
int currentLength = 1;
for (int i = 1; i < nums.length; i++) {
// Skip duplicates
if (nums[i] == nums[i - 1]) {
continue;
}
// Check if consecutive
if (nums[i] == nums[i - 1] + 1) {
currentLength++;
} else {
// Start new sequence
maxLength = Math.max(maxLength, currentLength);
currentLength = 1;
}
}
return Math.max(maxLength, currentLength);
}
Step-by-Step Execution: nums = [100,4,200,1,3,2]
Step 1: Sort array
[100, 4, 200, 1, 3, 2] β [1, 2, 3, 4, 100, 200]
Step 2: Scan for sequences
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
i=0: nums[0]=1
currentLength = 1
maxLength = 1
i=1: nums[1]=2
Compare with nums[0]=1
2 == 1+1 β Consecutive
currentLength = 2
i=2: nums[2]=3
Compare with nums[1]=2
3 == 2+1 β Consecutive
currentLength = 3
i=3: nums[3]=4
Compare with nums[2]=3
4 == 3+1 β Consecutive
currentLength = 4
maxLength = 4
i=4: nums[4]=100
Compare with nums[3]=4
100 != 4+1 β Not consecutive
Update maxLength = max(4, 4) = 4
Reset currentLength = 1
i=5: nums[5]=200
Compare with nums[4]=100
200 != 100+1 β Not consecutive
Update maxLength = max(4, 1) = 4
Reset currentLength = 1
Final check: max(4, 1) = 4
Result: 4
β° Time: O(n log n) - sorting dominates
πΎ Space: O(1) or O(n) depending on sort algorithm
β Approach 2: HashSet (Optimal)
The Breakthrough Insight π‘
Core Logic:
Key Observation:
We only need to start counting from the BEGINNING of sequences!
How to identify sequence start?
- A number is a sequence start if (num-1) is NOT in the array
Strategy:
1. Put all numbers in HashSet (O(n))
2. For each number:
- Check if num-1 exists in set
- If NO β this is a sequence start!
- Count consecutive numbers: num+1, num+2, num+3...
- Track maximum length
3. If YES β skip (we'll count from the start later)
Why this is O(n):
- Building set: O(n)
- Each number visited as potential start: O(n)
- Each number counted in sequence at most once
- Total: O(n)
Visual Explanation:
nums = [1, 2, 3, 4, 100, 200]
set = {1, 2, 3, 4, 100, 200}
Check 1: Is 0 in set? No β START!
Count: 1β2β3β4 (all in set)
Length: 4
Check 2: Is 1 in set? Yes β Skip (not a start)
Check 3: Is 2 in set? Yes β Skip
Check 4: Is 3 in set? Yes β Skip
Check 100: Is 99 in set? No β START!
Count: 100 (101 not in set)
Length: 1
Check 200: Is 199 in set? No β START!
Count: 200 (201 not in set)
Length: 1
Max: 4
Why This is Better: - O(n) time complexity (meets requirement!) - Each number checked at most twice - No sorting needed - O(n) space for HashSet (acceptable trade-off)
Implementation
public int longestConsecutive(int[] nums) {
if (nums.length == 0) return 0;
// Put all numbers in HashSet for O(1) lookup
HashSet<Integer> set = new HashSet<>();
for (int num : nums) {
set.add(num);
}
int maxLength = 0;
// Check each number as potential sequence start
for (int num : set) {
// Only start counting if this is the beginning of a sequence
if (!set.contains(num - 1)) {
int currentNum = num;
int currentLength = 1;
// Count how long the sequence goes
while (set.contains(currentNum + 1)) {
currentNum++;
currentLength++;
}
maxLength = Math.max(maxLength, currentLength);
}
}
return maxLength;
}
Step-by-Step Execution: nums = [100,4,200,1,3,2]
Step 1: Build HashSet
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Add 100 β set = {100}
Add 4 β set = {100, 4}
Add 200 β set = {100, 4, 200}
Add 1 β set = {100, 4, 200, 1}
Add 3 β set = {100, 4, 200, 1, 3}
Add 2 β set = {100, 4, 200, 1, 3, 2}
Final set: {100, 4, 200, 1, 3, 2}
Step 2: Find longest sequence
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Check num=100:
ββ Is 99 in set? No β This is a sequence START!
ββ currentNum = 100, currentLength = 1
ββ Is 101 in set? No
ββ Sequence: [100]
ββ maxLength = max(0, 1) = 1
Check num=4:
ββ Is 3 in set? Yes β NOT a start, skip
ββ (Will be counted when we process 1)
Check num=200:
ββ Is 199 in set? No β This is a sequence START!
ββ currentNum = 200, currentLength = 1
ββ Is 201 in set? No
ββ Sequence: [200]
ββ maxLength = max(1, 1) = 1
Check num=1:
ββ Is 0 in set? No β This is a sequence START!
ββ currentNum = 1, currentLength = 1
ββ Is 2 in set? Yes β currentNum=2, currentLength=2
ββ Is 3 in set? Yes β currentNum=3, currentLength=3
ββ Is 4 in set? Yes β currentNum=4, currentLength=4
ββ Is 5 in set? No β Stop
ββ Sequence: [1, 2, 3, 4]
ββ maxLength = max(1, 4) = 4
Check num=3:
ββ Is 2 in set? Yes β NOT a start, skip
ββ (Already counted in sequence starting at 1)
Check num=2:
ββ Is 1 in set? Yes β NOT a start, skip
ββ (Already counted in sequence starting at 1)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π― FINAL RESULT: 4
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Another Example: nums = [0,3,7,2,5,8,4,6,0,1]
Build set: {0, 3, 7, 2, 5, 8, 4, 6, 1}
(Duplicate 0 handled automatically)
Check num=0:
Is -1 in set? No β START!
Count: 0β1β2β3β4β5β6β7β8
Length: 9 β
Check num=3:
Is 2 in set? Yes β Skip
Check num=7:
Is 6 in set? Yes β Skip
(All other numbers have predecessor in set, so skipped)
Result: 9
β° Time: O(n) - each number visited at most twice
πΎ Space: O(n) - HashSet storage
π Edge Cases
Case 1: Empty array
Input: []
Output: 0
Strategy: Handle at beginning
Case 2: Single element
Input: [1]
Output: 1
Case 3: All consecutive
Input: [1,2,3,4,5]
Output: 5
Case 4: No consecutive (all isolated)
Input: [1,3,5,7,9]
Output: 1
Strategy: Each number is its own sequence
Case 5: Duplicates
Input: [1,2,2,3]
Output: 3
Strategy: HashSet automatically handles duplicates
Case 6: Negative numbers
Input: [-1,0,1,2]
Output: 4
Strategy: Algorithm works with any integers
Case 7: Large gaps
Input: [1,2,3,100,101,102]
Output: 3
Strategy: Two separate sequences
Case 8: Descending order
Input: [5,4,3,2,1]
Output: 5
Strategy: Order doesn't matter, still forms sequence
Case 9: Single very long sequence
Input: [1,2,3,...,100000]
Output: 100000
Strategy: O(n) handles efficiently
Common Mistakes
Mistake 1: Counting each number separately
β Wrong: Start count from every number
β Right: Only start from sequence beginning (num-1 not in set)
Mistake 2: Not handling duplicates
β Wrong: Count duplicates as extending sequence
β Right: HashSet automatically removes duplicates
Mistake 3: Using sorting and claiming O(n)
β Wrong: Sort then scan - this is O(n log n)
β Right: Use HashSet for O(n)
Mistake 4: Not checking if sequence start
β Wrong:
for (int num : nums) {
int length = 1;
while (set.contains(num + 1)) { ... }
}
β Right: Check if num-1 exists first
Mistake 5: Integer overflow in num+1
β Wrong: Not considering Integer.MAX_VALUE
β Right: Use long or check bounds (rare in practice)
Mistake 6: Modifying set while iterating
β Wrong: Remove elements during iteration
β Right: Just read from set, don't modify
π― Key Takeaways
β‘ Algorithm Comparison
Approach 1: Sorting
Time: O(n log n)
Space: O(1)
Use: When O(n log n) acceptable
Issue: Violates O(n) requirement
Approach 2: HashSet (OPTIMAL)
Time: O(n)
Space: O(n)
Use: Required for this problem
Benefit: Meets time complexity requirement
π The Core Insight
Key observation: Only count from sequence STARTS
Sequence start detection:
β num is start if (num-1) NOT in set
Why O(n) time:
- Build set: O(n)
- Each number checked as start: O(n)
- Each number counted in sequence: O(1) amortized
- A number is only counted once (as part of its sequence)
Total: O(n) + O(n) = O(n)
The trick: Skip non-start numbers!
β 2 is not a start if 1 exists
β 3 is not a start if 2 exists
β Only count from 1 (the start)
π― Pattern Recognition
Problem Type: Finding Consecutive Elements
Core Pattern: HashSet for O(1) lookup + Smart iteration
When to Apply:
β Need to find consecutive sequences
β Array is unsorted
β O(n) time required
β Duplicates may exist
β Order doesn't matter
Key Techniques:
β HashSet for O(1) contains check
β Sequence start detection (num-1 not in set)
β Count forward from starts only
β Amortized O(n) analysis
Related Problems:
- Binary Tree Longest Consecutive Sequence (LC 298)
- Longest Consecutive Sequence II (LC 549)
- Minimum Number of Operations to Make Array Continuous (LC 2009)
π§ Interview Strategy
Step 1: "Need longest consecutive sequence in unsorted array"
Step 2: "Sorting works but is O(n log n) - not O(n)"
Step 3: "Key insight: use HashSet for O(1) lookup"
Step 4: "Only count from sequence starts (num-1 not in set)"
Step 5: "Each number visited at most twice β O(n) total"
π Quick Revision Notes
π― Core Concept:
Use HashSet for O(1) lookups. Only count sequences from their start (when num-1 not in set). Count forward from each start.
β‘ Quick Implementation:
public int longestConsecutive(int[] a) {
if(a.length == 0) {
return 0;
}
// // Approach 1 - sort and find the length of LCS
// Arrays.sort(a); // 100,4,200,1,3,2 -> 1,2,3,4,100,200
// int res = 1;
// int count = 1;
// for(int i = 1; i < a.length; i++) {
// if(a[i] == a[i - 1] + 1) {
// count++;
// } else if (a[i] == a[i - 1]) {
// continue;
// } else {
// res = Math.max(count, res);
// count = 1;
// }
// }
// return Math.max(count, res);
// Approach 2 - hashing
Set<Integer> set = new HashSet<>();
for(int num : a) {
set.add(num);
}
// You need to start the count from lowest number in the LCS.
// So, if we find a number (curr - 1) less than current number (curr), skip the curr
// and wait till (curr - 1) is not found.
int count = 0;
int res = 0;
for(int num : set) {
// there is a sequence exists. Hence, skip
if(set.contains(num - 1)) {
continue;
} else {
count++; // count the current one
num++; // find for the next one if exits and increment the count
while (set.contains(num)) {
count++;
num++;
}
// once done, update res
res = Math.max(count, res);
count = 0;
}
}
return res;
}
π Key Insights:
- HashSet enables O(1) lookups
- Sequence start:
num-1not in set - Only count from starts to avoid redundancy
- Each number visited at most twice (once as start check, once in counting)
- O(n) time amortized - meets requirement!
- Duplicates handled automatically by HashSet
- Order irrelevant - algorithm finds sequences regardless
πͺ Memory Aid:
"Start from the beginning (num-1 missing), count forward!"
Think: "Skip if not start, count once per sequence"
Related Patterns
- Binary Tree Longest Consecutive Sequence (LC 298)
- Longest Consecutive Sequence II (LC 549)
- Minimum Operations to Make Array Continuous (LC 2009)
Happy practicing! π―