Alkesh

LeetCode - Longest Consecutive Subsequence

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.

Problem statement taken from: https://leetcode.com/problems/longest-consecutive-sequence

Example 1:

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:

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

Explanation

Sorting

The naive solution is to sort the array and find the longest consecutive elements. After sorting the array, we remove the duplicate elements. We run a loop that counts the current number and maximum length of the consecutive elements. If the current number is not a consecutive element of the previous one, we reset the counter to 1 and update the maximum length.

A C++ snippet of the above approach is as below:

int ans = 0, count = 0;

sort(array, array + n);

vector<int> v;
v.push_back(array[0]);

for (int i = 1; i < n; i++) {
    if (array[i] != array[i - 1])
        v.push_back(array[i]);
}

for (int i = 0; i < v.size(); i++) {
    if (i > 0 && v[i] == v[i - 1] + 1)
        count++;
    else
        count = 1;

    ans = max(ans, count);
}

return ans;

The time complexity of the above approach is O(n(logn)) and space complexity is O(n).

HashMap

We can reduce the time complexity to O(n) by using a HashMap. Let's check the algorithm directly.

- set n = nums.size()

- if n == 0
    return 0

- initialize map: map<int, int> m

- loop for i = 0; i < n; i++
  - m[nums[i]]++

- set prev = m.begin()
      maxLength = 1
      result = 0

- loop for i = m.begin(); i < m.end(); i++
  - if prev->first + 1 == i->first
    - maxLength++
  - else
    - result = max(result, maxLength)
    - maxLength = 1

  - prev = i

- return max(result, maxLength)

The time complexity of the above approach is O(n), and the space complexity is O(n).

Let's check our algorithm in C++, Golang, and Javascript.

C++ solution

class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        int n = nums.size();
        if(n == 0) return 0;

        map<int, int> m;

        for(int i = 0; i < n; i++) {
            m[nums[i]];
        }

        auto prev = m.begin();
        int maxLength = 1, result = 0;

        for(auto i = m.begin(); i != m.end(); i++) {
            if(prev->first + 1 == i->first) {
                maxLength++;
            } else {
                result = max(result, maxLength);
                maxLength = 1;
            }

            prev = i;
        }

        return max(result, maxLength);
    }
};

Golang solution

func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}

func longestConsecutive(nums []int) int {
    n := len(nums)
    if n == 0 {
        return 0
    }

    m := make(map[int]int)

    for i := 0; i < n; i++ {
        m[nums[i]]++
    }

    maxLength, result := 1, 0

    for num := range m {
        if _, ok := m[num-1]; !ok {
            currNum := num
            maxLength = 1

            for {
                if _, ok := m[currNum+1]; ok {
                    currNum += 1
                    maxLength += 1
                } else {
                    break
                }
            }

            result = max(result, maxLength)
        }
    }

    return result
}

Javascript solution

var longestConsecutive = function(nums) {
    const n = nums.length;
    if(n === 0) {
        return 0
    }

    let set = new Set(nums)

    let maxLength = 1, result = 0

    for(let num of set) {
        if(set.has(num - 1)) {
            continue;
        }

        let current = num
        maxLength = 1

        while(set.has(current + 1)){
            current++
            maxLength++
        }

        result = Math.max(result, maxLength)
    }

    return result
};

Dry Run

Let's dry-run our algorithm for Example 1.

Input: nums = [100, 4, 200, 1, 3, 2]

Step 1: int n = nums.size()
            n = 6

Step 2: n == 0
        6 == 0
        false

Step 3: map<int, int> m
        for(int i = 0; i < n; i++) {
            m[nums[i]];
        }

        m = {
            100: 0,
            4: 0,
            200: 0,
            1: 0,
            3: 0,
            2: 0,
        }

Step 4: prev = m.begin()
             = 1
        maxLength = 1
        result = 0

Step 5: loop for i = m.begin(); i != m.end()
            i = 1
            1 != m.end()
            true

            if prev->first + 1 == i->first
               1 + 1 == 1
               2 == 1
               false

            else
                result = max(result, maxLength)
                       = max(0, 1)
                       = 1

                maxLength = 1

            prev = i
                 = 1

            i++
            i -> 2

Step 6: loop for i != m.end()
            i = 2
            2 != m.end()
            true

            if prev->first + 1 == i->first
               1 + 1 == 2
               2 == 2
               true

               maxLength++
               maxLength = 2

            prev = i
                 = 2

            i++
            i -> 3

Step 7: loop for i != m.end()
            i = 3
            3 != m.end()
            true

            if prev->first + 1 == i->first
               2 + 1 == 3
               3 == 3
               true

               maxLength++
               maxLength = 3

            prev = i
                 = 3

            i++
            i -> 4

Step 8: loop for i != m.end()
            i = 4
            4 != m.end()
            true

            if prev->first + 1 == i->first
               3 + 1 == 4
               4 == 4
               true

               maxLength++
               maxLength = 4

            prev = i
                 = 4

            i++
            i -> 100

Step 9: loop for i != m.end()
            i = 100
            100 != m.end()
            true

            if prev->first + 1 == i->first
               4 + 1 == 100
               5 == 100
               false

            else
                result = max(result, maxLength)
                       = max(1, 4)
                       = 4

                maxLength = 1

            prev = i
                 = 100

            i++
            i -> 200

Step 10: loop for i != m.end()
            i = 200
            200 != m.end()
            true

            if prev->first + 1 == i->first
               100 + 1 == 200
               101 == 200
               false

            else
                result = max(result, maxLength)
                       = max(4, 4)
                       = 4

                maxLength = 4

            prev = i
                 = 200

            i++
            i -> end

Step 11: loop for i != m.end()
            false

Step 12: return max(result, maxLength)

We return the answer as 4.
Share this post!