Longest Increasing Subsequence

Interview Problems Intermediate 2 min read Published
Medium Dynamic Programming Often asked at: Microsoft, Amazon, Google, Meta, Apple, Samsung
In this lesson

A DP classic with a famous speed-up that interviewers love to ask about.

The problem#

Return the length of the longest strictly increasing subsequence of nums. A subsequence keeps the original order but may skip items.

Examples#

numsanswerone LIS
[10, 9, 2, 5, 3, 7, 101, 18]42, 3, 7, 18
[0, 1, 0, 3, 2, 3]40, 1, 2, 3
[7, 7, 7, 7]17

Hints#

Hint 1

Let best[i] = length of the longest increasing subsequence that ENDS at index i.

Hint 2

best[i] = 1 + the largest best[j] for j < i with nums[j] < nums[i].

Hint 3

For O(n log n): keep tails[k] = smallest possible ending value of an increasing subsequence of length k + 1, and binary search where each number fits.

The easy idea: every number joins the best line it can#

Walk left to right. Each number looks back at all earlier, smaller numbers and asks: “Whose sequence can I extend to become the longest?” It joins that one, adding 1.

ivaluecan extend afterbest[i]
010nothing1
19nothing1
22nothing1
3522
4322
575 or 33
610174
71874

Solution 1: DP, O(n²)#

def length_of_lis(nums):
    best = [1] * len(nums)
    for i in range(len(nums)):
        for j in range(i):
            if nums[j] < nums[i]:
                best[i] = max(best[i], best[j] + 1)
    return max(best, default=0)

print(length_of_lis([10, 9, 2, 5, 3, 7, 101, 18]))  # 4
print(length_of_lis([0, 1, 0, 3, 2, 3]))            # 4
print(length_of_lis([7, 7, 7, 7]))                  # 1

Solution 2: patience sorting, O(n log n)#

Deal the numbers like cards into piles. Each card goes on the leftmost pile whose top card is ≥ it; if none, start a new pile on the right. The number of piles is the LIS length. tails stores the top card of each pile, which is always sorted, so binary search finds the spot.

from bisect import bisect_left

def lis_fast(nums):
    tails = []
    for x in nums:
        i = bisect_left(tails, x)
        if i == len(tails):
            tails.append(x)       # new, longer pile
        else:
            tails[i] = x          # smaller top for that length
    return len(tails)

print(lis_fast([10, 9, 2, 5, 3, 7, 101, 18]))  # 4
print(lis_fast([0, 1, 0, 3, 2, 3]))            # 4

tails is not the actual subsequence; only its length is meaningful. Say that clearly if asked.

Complexity#

MethodTimeSpace
DPO(n²)O(n)
Patience sortingO(n log n)O(n)

Similar problems#

Number of Longest Increasing Subsequence, Russian Doll Envelopes, Longest Common Subsequence, Maximum Length of Pair Chain.

Learn the pattern: Dynamic Programming.

Quick quiz

3 questions. Check what stuck and earn 2 XP for each right answer.

1Simple DP complexity?
2Faster approach?
3Answer for [10,9,2,5,3,7,101,18]?

Progress is saved in this browser. Create a free account to keep it on every device.