一、题目描述
二、解题方法
1、使用递归(暴搜)+ 记忆化搜索
算法思路:
暴搜:
- 递归含义:dfs递归函数的作用,给他⼀个数 i ,返回以 i 位置为起点的最长递增子序列的长度;
-
函数体: 遍历 i 后面的所有位置,看看谁能加到 i 这个元素的后面(即看看谁能满足题目要求:递增的子序列)。 统计所有情况下的最大值 。
-
递归出口: 因为我们是判断之后再进入递归的,因此没有出口。
记忆化搜索:
- 加上⼀个备忘录(本题只需一个一维数组,如在递归返回前,用memo[i]来存放以 i 位置为起点的最长递增子序列的长度);
- 每次进入递归的时候,去备忘录里面看看;
- 每次返回的时候,将结果加入到备忘录里面。
2、递归(暴搜)+ 记忆化搜索 转为 动态规划
-
递归含义 -> 状态表示;
-
函数体 -> 状态转移方程;
-
递归出口 -> 初始化。
三、代码
1、使用递归(暴搜)+ 记忆化搜索
class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
int[] memo = new int[n];
int ret = 0;
for(int i = 0; i < n; i++) {
ret = Math.max(ret, dfs(i,nums,memo));
}
return ret;
}
public int dfs(int pos, int[] nums, int[] memo) {
if(memo[pos] != 0) {
return memo[pos];
}
int ret = 1;
for(int i = pos + 1; i < nums.length; i++) {
if(nums[i] > nums[pos]) {
ret = Math.max(ret, dfs(i,nums,memo) + 1);
}
}
memo[pos] = ret;
return ret;
}
}
2、动态规划
class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
Arrays.fill(dp,1);
int ret = 0;
for(int i = n-1; i >= 0; i--) {
for(int j = i+1; j < n; j++) {
if(nums[j] > nums[i]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
ret = Math.max(ret, dp[i]);
}
return ret;
}
}
上面的动态规划代码是以 i 位置为起点的。
下面我们来看一下,以 i 位置为终点的动态规划代码:
class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
for(int i = 0; i < n; i++) {
dp[i] = 1;
}
int ret = 0;
for(int i = 1; i < n; i++) {
for(int j = 0; j < i; j++) {
if(nums[i] > nums[j]) {
dp[i] = Math.max(dp[j] + 1, dp[i]);
}
}
ret = Math.max(ret, dp[i]);
}
//ret只是dp[i]~dp[n-1]的最大值,还要跟dp[0]比较一下
return ret > dp[0] ? ret : dp[0];
}
}