前言
一、分析题目
给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例 1:
示例:
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
说明:
- 可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
- 你算法的时间复杂度应该为 O(n2) 。
关于求最长上升子序列类的题目,大家应该也是比较常见的,面试的时候也是比较容易出现的,所以大家这块一定要多加重视!!!
动态规划满足三个性质:最优子结构、无后效性和大量重复子问题。
关于这个三个性质的解释,可以参考知乎的这篇文章:怎样学好动态规划?
二、解题思路
1.找出DP状态
根据题意和示例可以看出,求的是一个串的最长连续子序列,也就是所谓的上升排序,因此我们可以如下制定「DP 状态」,f [i]
表示仅考虑前i个数,以第 i 个数为结尾的最长上升子序列的最大长度。
2.找出DP状态转移方程
确定完「DP 状态」后,继续确定「DP 转移方程」。
「DP 转移方程」:
f[i] = max(f[i-1]+1,1)
该模型「DP 状态」的关键在于固定了最后一个数字,而这样做的原因在于对于一个最长上升子序列,我们只需要关注它最后一个数字,对于其前面的数字我们并不关心。
3.代码部分
1.Java版本
class Solution {
public int lengthOfLIS(int[] nums) {
if (nums.length == 0) {//判断数组为空
return 0;
}
int[] dp = new int[nums.length];//定义dp数组
//dp[0] = 1;
int maxans = 1;
for (int i = 0; i < nums.length; i++) {
dp[i] = 1;//初始化当前节点的最长上升子序列为1
for (int j = 0; j < i; j++) {//遍历计算到当前位置的最长上升子序列
if (nums[i] > nums[j]) {//如果大于当前节点,那么dp就加一
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
maxans = Math.max(maxans, dp[i]);
}
return maxans;
}
}
2.C++版本
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int sz = nums.size(), ans = 0;
vector<int> f(sz, 0);
for(int i = 0; i < sz; i++) {
int tmp = 1;
for(int j = i-1; j >= 0; j--) {//与java版本类型,只不过这里是从当前往前遍历
if(nums[i] > nums[j])
tmp = max(tmp, f[j]+1);
}
f[i] = tmp;
ans = max(ans, tmp);//每次遍历后与ans比较,存最长的个数
}
return ans;
}
};
3.Python代码
class Solution(object):
def lengthOfLIS(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
length = len(nums)
result = []
for i in range(length):
result.append(1)
for j in range(0,i):
if nums[i]>nums[j]:
result[i] = max(result[i],result[j]+1)
return max(result)
相比之下,Python代码最简洁,但是时间是最慢的。
三、总结
提示:这个题在动态规划里面算一个中等难度的题目,感觉这块内容确实比较让头头大,只能多做题,多总结了。
记录时间:2020年12月2日