地址:https://leetcode-cn.com/problems/longest-increasing-subsequence/
我写的题解地址:https://leetcode-cn.com/problems/longest-increasing-subsequence/solution/dong-tai-gui-hua-er-fen-cha-zhao-tan-xin-suan-fa-p/
方法一:动态规划
- 状态定义:
dp[i]
表示以nums[i]
结尾的“最长上升子序列”的长度;
怎么想到的?状态转移方程好推导。
- 状态转移方程:
解释:在所有位于索引位置 i
前面比 nums[i]
小的数的后面。
- 初始化:
dp[0] = 1
,单独一个数是一个子序列; - 输出:整个数组
dp
中的最大值。
Java 代码:
import java.util.Arrays;
public class Solution2 {
public int lengthOfLIS(int[] nums) {
// 特判
int len = nums.length;
if (len == 0) {
return 0;
}
// dp[i]:以 nums[i] 结尾的最长上升子序列的长度
int[] dp = new int[len];
Arrays.fill(dp, 1);
for (int i = 1; i < len; i++) {
for (int j = 0; j < i; j++) {
if (nums[j] < nums[i]) {
dp[i] = Math.max(dp[i], 1 + dp[j]);
}
}
}
int res = dp[0];
for (int i = 1; i < len; i++) {
res = Math.max(res, dp[i]);
}
return res;
}
}
方法二:记忆化搜索
Java 代码:
import java.util.Arrays;
/**
* 记忆化递归,代码看起来有点臃肿
* 时间复杂度:O(n^2)
* 空间复杂度:O(n)
*/
public class Solution {
/**
* 以 nums[i] 结尾的最长上升子序列的长度
*/
private int[] memo;
public int lengthOfLIS(int[] nums) {
// 特判
int len = nums.length;
if (len == 0) {
return 0;
}
memo = new int[len];
Arrays.fill(memo, -1);
int res = 1;
for (int i = 0; i < len; i++) {
res = Math.max(res, getMaxLength(nums, i));
}
return res;
}
private int getMaxLength(int[] nums, int index) {
if (memo[index] != -1) {
return memo[index];
}
int res = 1;
for (int i = 0; i < index; i++) {
if (nums[i] < nums[index]) {
res = Math.max(res, 1 + getMaxLength(nums, i));
}
}
return memo[index] = res;
}
}