Dynamic programming / Intermediate
Longest Increasing Subsequence Visualizer
dp[i] is the length of the longest increasing run that ends exactly at a[i]. Look back at every j < i with a smaller value and extend the best one.
Start the Longest Increasing Subsequence simulation → Step forward and back, change the input, follow the code line by line in Java, Python, C++, C or JavaScript. Free, no sign-up.
Time and space complexity
| Best time | O(n²) |
|---|---|
| Average time | O(n²) |
| Worst time | O(n²) |
| Extra space | O(n) |
Worked example, step by step
The same steps the simulator shows, on a small input.
- dp[i] will hold the longest increasing subsequence that ends at a[i].
- Every value alone is a run of length 1, so dp[0] starts at 1.
- dp[0] = 1. Best so far: 1.
- Every value alone is a run of length 1, so dp[1] starts at 1.
- 10 ≥ 9, so 9 can’t extend a run ending at 10.
- dp[1] = 1. Best so far: 1.
- Every value alone is a run of length 1, so dp[2] starts at 1.
- 10 ≥ 2, so 2 can’t extend a run ending at 10.
- 9 ≥ 2, so 2 can’t extend a run ending at 9.
- dp[2] = 1. Best so far: 1.
- Every value alone is a run of length 1, so dp[3] starts at 1.
- 10 ≥ 5, so 5 can’t extend a run ending at 10.
- 9 ≥ 5, so 5 can’t extend a run ending at 9.
- 2 < 5, so extend the run ending at 2: dp[3] = 1 + 1 = 2.
- dp[3] = 2. Best so far: 2.
- Every value alone is a run of length 1, so dp[4] starts at 1.
- 10 ≥ 3, so 3 can’t extend a run ending at 10.
- 9 ≥ 3, so 3 can’t extend a run ending at 9.
- 2 < 3, so extend the run ending at 2: dp[4] = 1 + 1 = 2.
- 5 ≥ 3, so 3 can’t extend a run ending at 5.
- … 22 more steps …
- 7 < 18, so extend the run ending at 7: dp[7] = 3 + 1 = 4.
- 101 ≥ 18, so 18 can’t extend a run ending at 101.
- dp[7] = 4. Best so far: 4.
- The longest increasing subsequence has length 4, for example 2, 5, 7, 101.
1D DP: longest increasing subsequence in Java, Python, C++, C and JavaScript
int lengthOfLIS(int[] a) {
int[] dp = new int[a.length];
int best = 0;
for (int i = 0; i < a.length; i++) {
dp[i] = 1;
for (int j = 0; j < i; j++) {
if (a[j] < a[i])
dp[i] = Math.max(dp[i], dp[j] + 1);
}
best = Math.max(best, dp[i]);
}
return best;
}
def length_of_lis(a):
dp = [0] * len(a)
best = 0
for i in range(len(a)):
dp[i] = 1
for j in range(i):
if a[j] < a[i]:
dp[i] = max(dp[i], dp[j] + 1)
best = max(best, dp[i])
return best
int lengthOfLIS(const vector<int>& a) {
vector<int> dp(a.size());
int best = 0;
for (int i = 0; i < (int)a.size(); i++) {
dp[i] = 1;
for (int j = 0; j < i; j++) {
if (a[j] < a[i])
dp[i] = max(dp[i], dp[j] + 1);
}
best = max(best, dp[i]);
}
return best;
}
int lengthOfLIS(int a[], int n) {
int dp[n];
int best = 0;
for (int i = 0; i < n; i++) {
dp[i] = 1;
for (int j = 0; j < i; j++) {
if (a[j] < a[i] && dp[j] + 1 > dp[i])
dp[i] = dp[j] + 1;
}
if (dp[i] > best) best = dp[i];
}
return best;
}
function lengthOfLIS(a) {
const dp = new Array(a.length);
let best = 0;
for (let i = 0; i < a.length; i++) {
dp[i] = 1;
for (let j = 0; j < i; j++) {
if (a[j] < a[i])
dp[i] = Math.max(dp[i], dp[j] + 1);
}
best = Math.max(best, dp[i]);
}
return best;
}In an interview
LeetCode 300, Longest Increasing Subsequence. Same shape: 354 Russian Doll Envelopes, 1048 Longest String Chain.
The follow-up is O(n log n): keep a list of the smallest possible tail for each length and binary-search where each value goes.