Longest Increasing Subsequence

Medium
92.

Longest Increasing Subsequence

Longest Increasing Subsequence is a medium coding problem on arrays, dynamic programming and binary search, asked in Intuit interviews.

Given an integer array nums, return the length of the longest strictly increasing subsequence.

Example 1

Input
nums = [10,9,2,5,3,7,101,18]
Output
4
Explanation
[2,3,7,101] (or [2,5,7,101]).

Example 2

Input
nums = [7,7,7,7,7,7,7]
Output
1

Constraints

  • 1 <= nums.length <= 30
  • -100 <= nums[i] <= 100

Follow-up: the O(n log n) 'patience sorting' solution keeps an array of smallest tail values.

Write your solution here. Running it against the tests needs a free account — what you type comes with you.Sign in to run
/**
 * @param {number[]} nums
 * @return {number}
 */
var lengthOfLIS = function(nums) {
    // Write your code here
    
};

Sign in to run your own test cases

Sign in

Longest Increasing Subsequence — Problem & Solution

Longest Increasing Subsequence solution explained: step-by-step approach, complexity and code in Python, Java, C++ and JavaScript. A medium problem.

Longest Increasing Subsequence is a medium coding problem on arrays, dynamic programming and binary search, asked in Intuit interviews.

Problem statement

Given an integer array nums, return the length of the longest strictly increasing subsequence.

Example 1

Input: nums = [10,9,2,5,3,7,101,18]
Output: 4
Explanation: [2,3,7,101] (or [2,5,7,101]).

Example 2

Input: nums = [7,7,7,7,7,7,7]
Output: 1

Constraints

  • 1 <= nums.length <= 30
  • -100 <= nums[i] <= 100

Follow-up: the O(n log n) 'patience sorting' solution keeps an array of smallest tail values.

Hints for Longest Increasing Subsequence

  1. Hint 1

    O(n²): dp[i] = 1 + max(dp[j]) over j < i with nums[j] < nums[i].

  2. Hint 2

    O(n log n): maintain tails[k] = smallest tail of an increasing subsequence of length k+1; binary-search each element in.

How to solve Longest Increasing Subsequence

Let best[i] be the length of the longest increasing subsequence ending exactly at index i. Any such subsequence's second-to-last element sits at some earlier index j with a smaller value, so best[i] = 1 + max(best[j]) over those j. The answer is the largest entry in the table.

Approach

  1. Set every best[i] to 1 — each element alone is a subsequence.
  2. For each i, scan all earlier j.
  3. If nums[j] < nums[i], the subsequence ending at j can be extended: take best[j] + 1 if it improves best[i].
  4. Return the maximum value in best.

Why it works

Anchoring the state at the ending index is what removes the ambiguity — subsequences are not contiguous, so "the best up to i" is not enough information to extend correctly, but "the best ending at i" is. Every increasing subsequence has a unique last element, so scanning all endpoints covers each exactly once. An O(n log n) variant keeps a list of the smallest possible tail value for each length and binary-searches it, which matters at larger inputs.

Complexity

  • Time — O(n^2)
  • Space — O(n)

Pitfalls

  • The comparison is strict (<); using <= counts equal values and turns this into non-decreasing subsequences.
  • The answer is the maximum over the whole table, not best[n-1] — the longest run need not end at the last element.
  • Initialise to 1, not 0; every element is a subsequence of length one.
  • An all-equal array answers 1, which is a good check of the strictness.

Reference solution

Python

from typing import List
import bisect

def lengthOfLIS(nums: List[int]) -> int:
    tails = []
    for x in nums:
        i = bisect.bisect_left(tails, x)
        if i == len(tails):
            tails.append(x)
        else:
            tails[i] = x
    return len(tails)

Java

public static int lengthOfLIS(int[] nums) {
    int n = nums.length;
    int[] best = new int[n];
    Arrays.fill(best, 1);
    int answer = 1;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < i; j++) {
            if (nums[j] < nums[i] && best[j] + 1 > best[i]) best[i] = best[j] + 1;
        }
        if (best[i] > answer) answer = best[i];
    }
    return answer;
}

C++

int lengthOfLIS(vector<int>& nums) {
    int n = (int) nums.size();
    vector<int> best(n, 1);
    int answer = 1;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < i; j++) {
            if (nums[j] < nums[i] && best[j] + 1 > best[i]) best[i] = best[j] + 1;
        }
        if (best[i] > answer) answer = best[i];
    }
    return answer;
}

JavaScript

var lengthOfLIS = function(nums) {
    const tails = [];
    for (const x of nums) {
        let lo = 0, hi = tails.length;
        while (lo < hi) {
            const mid = (lo + hi) >> 1;
            if (tails[mid] < x) lo = mid + 1;
            else hi = mid;
        }
        tails[lo] = x;
    }
    return tails.length;
};

Also on the editorial tab: C, C#, Go, Kotlin, PHP, Ruby, Rust, Swift, TypeScript.

All 1199 arrays problems · the whole catalogue

Learn the technique: Arrays · Dynamic Programming