Optimize the code · Medium

Speed Up Longest Consecutive Sequence

Medium Make it fast Most askedSeen at Google, Amazon, Meta

longestConsecutive(nums) returns the length of the longest run of consecutive integers that can be formed from the values in nums (in any order). For example [100, 4, 200, 1, 3, 2] contains 1, 2, 3, 4, so the answer is 4.

The version below is correct but searches the whole array for every next number. Make it O(n) without changing the results.

Example 1

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

Example 2

Input: nums = [0, 3, 7, 2, 5, 8, 4, 6, 0, 1]
Output: 9

The slow code

Every case must finish within 300 ms (budgets are per language in the editor).

function longestConsecutive(nums) {
  let best = 0;
  for (const x of nums) {
    let length = 1;
    let next = x + 1;
    while (nums.includes(next)) {
      length++;
      next++;
    }
    best = Math.max(best, length);
  }
  return best;
}

Hints

Hint 1

Replace the array search with a set lookup.

Hint 2

Only start counting from x when x - 1 is not in the set: then each run is walked exactly once.

Make it faster

Loading the editor… (JavaScript is required to run code in your browser.)

Solution and explanation

Show the solution

Time O(n) · Space O(n)

Why it is slow: every includes(x + 1) scans the whole array, and the loop starts a new walk from every element, so long runs are walked again from each of their members: O(n^2) or worse.

The fix: put the values in a hash set. For each value x, start a walk only if x - 1 is not in the set (so x begins a run), then count x + 1, x + 2, ... with O(1) lookups. Each value is visited by at most one walk, so the total is O(n).

Sorting first (O(n log n)) is a fine answer to mention, but the interviewer asking this question is looking for the O(n) set trick.

Optimized solution

function longestConsecutive(nums) {
  const set = new Set(nums);
  let best = 0;
  for (const x of set) {
    if (set.has(x - 1)) continue; // not the start of a run
    let y = x;
    while (set.has(y + 1)) y++;
    best = Math.max(best, y - x + 1);
  }
  return best;
}

Common mistakes

  • Starting a walk from every element: still O(n^2) in the worst case (one long run).
  • Not handling duplicates or the empty array.

Follow-up questions

  • Return the run itself, not its length.
  • Values arrive one by one: maintain the answer with union-find.