The Problem
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.
A consecutive sequence is a sequence of elements in which each element is exactly 1 greater than the previous element.
Examples
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.
Input: nums = [0, 3, 7, 2, 5, 8, 4, 6, 0, 1]
Output: 9
Constraints
- 0 <= nums.length <= 10^5
- -10^9 <= nums[i] <= 10^9
Brute Force Solution
func longestConsecutive(_ nums: [Int]) -> Int {
var res = 0
let setOfNums: Set<Int> = Set(nums)
for num in nums {
var streak = 0
var curr = num
while setOfNums.contains(curr) {
streak += 1
curr += 1
}
res = max(res, streak)
}
return res
}
Explanation
Let’s start with the brute force solution. We need to increment each element by 1
to check if the incremented value exists in our input array. For example, if we have an array nums
with [3, 2, 1, 100, 5]
, the longest consecutive sequence will be 3
.
If you look closely at the array [3, 2, 1, 100, 5]
, it has a sequence of 2, 1
, which when incremented forms elements that already exist in the array (1 -> 2, 2 -> 3)
. By counting the number of increments, you can determine the longest sequence. The solution above does exactly that:
- Iterates through the array of
nums
- Checks if the element exists in the array and updates
streak
by1
- Calculates the max of
res
andstreak
- Returns the result
This solution uses a set
to avoid duplicate values, which could lead to incorrect results.
Time/Space Complexity
- Time complexity: O(n^2)
- Space complexity: O(n)
Solution - 2 - Sorting
func longestConsecutive(_ nums: [Int]) -> Int {
if nums.isEmpty {
return 0
}
let n = nums.count
var nums = nums
nums.sort()
var res = 0
var curr = nums[0]
var streak = 0
var i = 0
while i < n {
if curr != nums[i] {
curr = nums[i]
streak = 0
}
while i < n && nums[i] == curr {
i += 1
}
streak += 1
curr += 1
res = max(res, streak)
}
return res
}
Explanation
The next way to solve this problem is by sorting. Sorting will transform your array, for example [3, 2, 1, 100, 5]
to [1, 2, 3, 5, 100]
. In this case, the longest sequence will be on the left side of the array, so you can iterate from left to right to find the result.
The condition if curr != nums[i]
checks if curr
value is not the same as the element nums[i]
and resets the streak
. The following steps are similar to the brute force solution.
Time/Space Complexity
- Time complexity: O(n log n)
- Space complexity: O(1)
Solution - 3 - Optimal
func longestConsecutive(_ nums: [Int]) -> Int {
var longestSCount = 0
let setOfNums: Set<Int> = Set(nums)
for num in setOfNums {
if !setOfNums.contains(num - 1) {
var length = 0
while setOfNums.contains(num + length) {
length += 1
}
longestSCount = max(length, longestSCount)
}
}
return longestSCount
}
Explanation
Let’s look at the optimal solution using the example input [1, 2, 3, 5, 100]
. When you look at it, you can recognise patterns such as elements 2, 3
having a neighbor on the left side. If you decrement each of them by 1
, you will see that values (1 <- 2
, 2 <- 3
) have a neighbor. After that, all you need is to calculate the length of the longest sequence.
This solution also uses a set
to avoid duplicate values, which would cause incorrect results.
Time/Space Complexity
- Time complexity: O(n)
- Space complexity: O(n)