Longest Increasing Subsequence
Given an integer array nums, return the length of the longest strictly increasing subsequence . dpi is the length of the longest increasing subsequence that ends exactly at index i. It is built from every earlier subproblem dpj where numsj is smaller than numsi — take the best of them and add one . The answer is the largest value anywhere in the table.
Constraints
- 1 ≤ nums.length ≤ 2500
- -104 ≤ numsi ≤ 104
Example
nums = [10, 9, 2, 5, 3, 7, 101, 18]4Explanation The longest increasing subsequence is [2, 3, 7, 101] (or [2, 3, 7, 18]), length 4.
In plain terms
- Subsequence
- A set of elements taken from an array in the same order they originally appear, even if other elements sit between them — for example, [1, 3, 4] is a subsequence of [1, 2, 3, 5, 4].
Build each cell from the best smaller subsequence before it
nums = [1, 3, 2, 4]. One cell per element, each starting at 1.
What happens in this step
nums = [1, 3, 2, 4] dp = [1, 1, 1, 1] (every element is a subsequence of length 1 by itself) The cell labels are the numbers themselves; the values are the best length ending at that number. dp[0] = 1 needs no predecessor — it is already final.
Steps to visualize
- Start every dpi at 1 — every element is an increasing subsequence of length 1 by itself.
- For each index i, look at every earlier index j where numsj < numsi.
- Set dpi to the largest dpj + 1 found across those earlier indices.
- The answer is the maximum value anywhere in the table.
Walk through the code
Same walkthrough, now with the code. Press Next to move one step and watch which lines run.
nums = [1, 3, 2, 4]. One cell per element, each starting at 1.
What happens in this step
nums = [1, 3, 2, 4] dp = [1, 1, 1, 1] (every element is a subsequence of length 1 by itself) The cell labels are the numbers themselves; the values are the best length ending at that number. dp[0] = 1 needs no predecessor — it is already final.
Solution
function lengthOfLIS(nums) {
const n = nums.length;
const dp = new Array(n).fill(1);
let best = 1;
for (let i = 1; i < n; i++) {
for (let j = 0; j < i; j++) {
if (nums[j] < nums[i] && dp[j] + 1 > dp[i]) {
dp[i] = dp[j] + 1;
}
}
best = Math.max(best, dp[i]);
}
return best;
}- Time
- O(n^2)
- Space
- O(n)
Test cases
| Input | Expected | Covers |
|---|---|---|
nums = [10, 9, 2, 5, 3, 7, 101, 18] | 4 | example from the docstring |
nums = [0, 1, 0, 3, 2, 3] | 4 | a second worked example with repeated values |
nums = [7, 7, 7, 7, 7, 7, 7] | 1 | every value equal, no strict increase possible |
nums = [5] | 1 | smallest valid input, a single element |
nums = [1, 2, 3, 4, 5] | 5 | the entire array is already increasing |
nums = [5, 4, 3, 2, 1] | 1 | the entire array is decreasing |
nums = [1, 2] | 2 | boundary case, two increasing elements |