Longest Consecutive Sequence
MedPrompt
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:
[1, 2, 3, 4]Example 2:
Input: nums = [0,3,7,2,5,8,4,6,0,1]
Output: 9Example 3:
Input: nums = [1,0,1,2]
Output: 3
Constraints:
0 <= nums.length <= 105-109 <= nums[i] <= 109
Approaches
3 approaches with complexity analysis and trade-offs.
This approach iterates through each number in the array. For each number, it attempts to build a sequence by repeatedly checking if the next consecutive number exists anywhere else in the array. This check is done via a linear scan.
Algorithm
- Initialize a variable
maxLengthto 0.\n- For each numbernumin the input arraynums:\n - InitializecurrentNum = numandcurrentLength = 1.\n - Start a loop:\n - Check ifcurrentNum + 1exists in thenumsarray by performing a linear scan.\n - If it exists, incrementcurrentLength, updatecurrentNumtocurrentNum + 1, and continue the loop.\n - If it does not exist, break the loop.\n - UpdatemaxLength = max(maxLength, currentLength).\n- After iterating through all numbers, returnmaxLength.
Walkthrough
The brute-force algorithm iterates through every number in the input array nums. For each number num, it assumes it could be the start of a consecutive sequence. It then enters a while loop, checking for the existence of num + 1, num + 2, and so on. The check for existence is performed by another linear scan through the entire array. The length of the current sequence is tracked, and the maximum length found across all possible starting numbers is returned. This method is straightforward to conceptualize but is highly inefficient due to the nested loops and repeated scans.\n\njava\nclass Solution {\n private boolean arrayContains(int[] arr, int num) {\n for (int i = 0; i < arr.length; i++) {\n if (arr[i] == num) {\n return true;\n }\n }\n return false;\n }\n\n public int longestConsecutive(int[] nums) {\n if (nums.length == 0) {\n return 0;\n }\n\n int longestStreak = 0;\n\n for (int num : nums) {\n int currentNum = num;\n int currentStreak = 1;\n\n while (arrayContains(nums, currentNum + 1)) {\n currentNum += 1;\n currentStreak += 1;\n }\n\n longestStreak = Math.max(longestStreak, currentStreak);\n }\n\n return longestStreak;\n }\n}\n
Complexity
Time
O(n^3)
Space
O(1)
Trade-offs
Pros
Simple to understand and implement.
Uses constant extra space, O(1).
Cons
Extremely inefficient with a time complexity of O(n^3), making it impractical for even moderately sized inputs.
Will result in a 'Time Limit Exceeded' error on most coding platforms.
This approach first sorts the array. After sorting, all the elements of a consecutive sequence will be grouped together, making it easy to find the longest sequence in a single linear pass over the sorted array.
Algorithm
- Handle the edge case of an empty array by returning 0.\n- Sort the input array
nums.\n- InitializemaxLength = 1andcurrentLength = 1.\n- Iterate through the sorted array from the second element (i = 1).\n- Ifnums[i]is not equal tonums[i-1](i.e., not a duplicate):\n - Check ifnums[i]is equal tonums[i-1] + 1.\n - If it is, incrementcurrentLength.\n - If it's not, the sequence is broken. UpdatemaxLength = max(maxLength, currentLength)and resetcurrentLength = 1.\n- After the loop finishes, updatemaxLengthone last time:maxLength = max(maxLength, currentLength).\n- ReturnmaxLength.
Walkthrough
The core idea is that if the numbers are sorted, we can easily find consecutive sequences by just iterating through the array once. The first step is to sort the input array nums. After sorting, we iterate through the array, keeping track of the current consecutive sequence length (currentLength) and the maximum length found so far (maxLength). We must handle duplicate numbers; if the current number is the same as the previous one, we simply ignore it. If the current number is one greater than the previous number, it extends the sequence, so we increment currentLength. If the sequence is broken (the current number is not one greater than the previous), we update maxLength with the currentLength and reset currentLength to 1 for the new sequence. A final check is needed after the loop to account for the longest sequence being at the end of the array.\n\njava\nimport java.util.Arrays;\n\nclass Solution {\n public int longestConsecutive(int[] nums) {\n if (nums.length == 0) {\n return 0;\n }\n\n Arrays.sort(nums);\n\n int longestStreak = 1;\n int currentStreak = 1;\n\n for (int i = 1; i < nums.length; i++) {\n if (nums[i] != nums[i-1]) {\n if (nums[i] == nums[i-1] + 1) {\n currentStreak += 1;\n } else {\n longestStreak = Math.max(longestStreak, currentStreak);\n currentStreak = 1;\n }\n }\n }\n\n return Math.max(longestStreak, currentStreak);\n }\n}\n
Complexity
Time
O(n log n)
Space
O(1) or O(log n)
Trade-offs
Pros
Much more efficient than the brute-force approach.
Relatively easy to implement once the sorting idea is clear.
Space efficient, especially with in-place sorting algorithms.
Cons
The time complexity is dominated by sorting, which is O(n log n). This does not meet the problem's requirement of an O(n) solution.
This approach achieves linear time complexity by using a Hash Set for fast O(1) lookups. It intelligently avoids redundant work by only building sequences from their starting numbers (i.e., a number x where x-1 is not present).
Algorithm
- If the input array is empty, return 0.\n- Create a
HashSetand add all elements ofnumsto it.\n- InitializemaxLength = 0.\n- Iterate through eachnumin the set.\n- Check ifset.contains(num - 1). If it does,numis not the start of a sequence, so continue to the next number.\n- Ifnum - 1is not in the set, we have found the start of a sequence.\n- InitializecurrentNum = numandcurrentLength = 1.\n- Whileset.contains(currentNum + 1):\n - IncrementcurrentLengthand updatecurrentNumtocurrentNum + 1.\n- After the while loop, updatemaxLength = max(maxLength, currentLength).\n- After iterating through all numbers, returnmaxLength.
Walkthrough
This method provides an optimal solution with O(n) time complexity as required by the problem. First, all numbers from the input array are inserted into a HashSet. This allows for checking the presence of a number in average O(1) time. Then, the algorithm iterates through the numbers. For each number num, it performs a crucial check: if num - 1 also exists in the set. If it does, it means num is part of a sequence we have already counted or will count starting from a smaller number, so we skip it. This check is the key to achieving O(n) time complexity, as it ensures we only start building a sequence from its absolute smallest element. If num - 1 is not in the set, we start counting a new sequence. We use a while loop to check for num + 1, num + 2, etc., in the set, incrementing a counter. The maximum length is updated after each full sequence is counted. Although there is a nested loop, each number is visited at most twice, leading to a linear time complexity overall.\n\njava\nimport java.util.HashSet;\nimport java.util.Set;\n\nclass Solution {\n public int longestConsecutive(int[] nums) {\n if (nums == null || nums.length == 0) {\n return 0;\n }\n\n Set<Integer> numSet = new HashSet<>();\n for (int num : nums) {\n numSet.add(num);\n }\n\n int longestStreak = 0;\n\n for (int num : numSet) {\n // Only start counting if 'num' is the beginning of a sequence\n if (!numSet.contains(num - 1)) {\n int currentNum = num;\n int currentStreak = 1;\n\n while (numSet.contains(currentNum + 1)) {\n currentNum += 1;\n currentStreak += 1;\n }\n\n longestStreak = Math.max(longestStreak, currentStreak);\n }\n }\n\n return longestStreak;\n }\n}\n
Complexity
Time
O(n)
Space
O(n)
Trade-offs
Pros
Achieves the optimal O(n) time complexity, satisfying the problem's constraints.
The logic is elegant, avoiding redundant computations by only checking sequences from their starting points.
Cons
Requires extra space of O(n) for the hash set, whereas the sorting approach can be done in-place.
Solutions
Solution
class Solution { public int longestConsecutive ( int [] nums ) { Set < Integer > s = new HashSet <>(); for ( int x : nums ) { s . add ( x ); } int ans = 0 ; for ( int x : nums ) { if (! s . contains ( x - 1 )) { int y = x + 1 ; while ( s . contains ( y )) { ++ y ; } ans = Math . max ( ans , y - x ); } } return ans ; } }/** * @param {number[]} nums * @return {number} */ var longestConsecutive = function (nums) { const s = new Set(nums); let ans = 0; for (const x of nums) { if (!s.has(x - 1)) { let y = x + 1; while (s.has(y)) { y++; } ans = Math.max(ans, y - x); } } return ans; };class Solution { public: int longestConsecutive ( vector < int >& nums ) { unordered_set < int > s ( nums . begin (), nums . end ()); int ans = 0 ; for ( int x : nums ) { if ( ! s . count ( x - 1 )) { int y = x + 1 ; while ( s . count ( y )) { y ++ ; } ans = max ( ans , y - x ); } } return ans ; } };class Solution : def longestConsecutive ( self , nums : List [ int ]) -> int : s = set ( nums ) ans = 0 for x in nums : if x - 1 not in s : y = x + 1 while y in s : y += 1 ans = max ( ans , y - x ) return ansVideo walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.