The Problem
Given an integer array nums
, return the length of the longest strictly increasing subsequence.
Check LeetCode link for more details and example input & output.
Dynamic Programming Solutions
A Recursive Approach
Comparing with the original problem, it’s easier to solve the longest increasing subsequence
which starts at the index i
recursively. Let’s call it LIS[i]
, longest increasing subsequence
of nums
starting at the index i
.
The original problem becomes finding the maximum value among LIS[0]
, LIS[1]
, …, LIS[nums.length - 1]
.
public int lengthOfLIS(int[] nums) {
int max = 1;
for (int i = 0; i < nums.length; i++) {
max = Math.max(max, lengthOfLISStartAtIndex(nums, i));
}
return max;
}
int lengthOfLISStartAtIndex(int[] nums, int index) {
if (index == nums.length - 1) { // the base case
return 1;
}
int result = 1;
for (int i = index + 1; i < nums.length; i++) {
// this test guarantees getting an increasing sub-sequence
if (nums[i] > nums[index]) {
result = Math.max(result, 1 + lengthOfLISStartAtIndex(nums, i));
}
}
return result;
}
A Top Down Approach
Improve the recursive solution with caching.
public int lengthOfLIS(int[] nums) {
Map<Integer, Integer> cache = new HashMap<>();
int result = 1;
for (int i = 0; i < nums.length; i++) {
result = Math.max(result, lengthOfLIS(nums, i, cache));
}
return result;
}
// length Of LIS starting at `index`
int lengthOfLIS(int[] nums, int index, Map<Integer, Integer> cache) {
if (index == nums.length - 1) {
return 1;
}
if (cache.get(index) != null) {
return cache.get(index);
}
int result = 1;
for (int i = index + 1; i < nums.length; i++) {
if (nums[i] > nums[index]) {
result = Math.max(result, 1 + lengthOfLIS(nums, i, cache));
}
}
cache.put(index, result);
return result;
}
A Bottom Up Approach
It’s easy to calculate LIS[i]
using a bottom up approach too.
LIS[i]
is the maximum of below values.
- 1 (since at least
nums[i]
is a candidate of LIS starting ati
) 1 + LIS[i+1]
, ifnums[i]
<nums[i+1]
1 + LIS[i+2]
, ifnums[i]
<nums[i+2]
- …
Base case is LIS[nums.length - 1]
is 1
.
Below is a Java solution.
public int lengthOfLIS(int[] nums) {
int[] dp = new int[nums.length];
Arrays.fill(dp, 1);
int result = 1;
for (int i = nums.length - 2; i >= 0; i--) {
for (int j = i + 1; j < nums.length; j++) {
if (nums[i] < nums[j]) {
dp[i] = Math.max(dp[i], 1 + dp[j]);
}
}
// record the maximum value of LIS[0], LIS[1], ...
result = Math.max(result, dp[i]);
}
return result;
}
The time complexity is O(n^2)
.