LeetCode 300. 最长递增子序列
这道题可以说多次出现在了我的刷题生涯当中。依据我的个人经验,从本科的时候备战蓝桥杯、备战天梯赛,到如今刷 LeetCode 准备面试,最长递增子序列一定是 DP 当中绕不开的一道题。
我发现这道题尽管做过很多次,甚至整理过很多次,但是每一次重新打开这道题目的时候,都需要再看一遍上次解题的思路才能顺利做出来,看一眼之前的代码片便恍然大悟,遂通过本文对这道题目的所用到的 DP 思想进行详细的整理。
题目描述
题目描述不需要过多赘述了,一个简单的例子是:
1 0 2 0 3 0 108 9
这个序列的最长递增子序列的长度是4
,可能的最长递增子序列包括[1, 2, 3, 108]
和[1, 2, 3, 9]
。
思路
使用 DP 来解决这个问题。
具体来说,需要开一个一维数组,数组当中每个位置的值,也就是 DP 每一位的状态,表示的就是到这个数位为止最长递增子序列的长度。
那么我们应该如何维护这个状态呢?
其实很简单,比如对于 1 0 2 0 3 0 108 9
这个例子,当我们维护到 108
这个数对应位置的状态时,直接从头开始遍历数组直到这个位置,假设当前这个位置的下标为 i
,使用 j
表示遍历数组的移动下标,那么当前位置的 DP 数组状态为 dp[i] = max(dp[i], dp[j] + 1)
。原因是当前位置的最长递增子序列的长度要么是自己本身,要么是前面那个比当前位置更小的数加上一。
最后找到 DP 数组当中的最大元素就是最终的答案。
C++ 代码
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n = nums.size();
vector<int> dp(n, 0);
for(int i=0; i<n; i++) {
dp[i] = 1;
for(int j=0; j<i; j++) {
if(nums[j] < nums[i]) {
dp[i] = max(dp[i], dp[j] + 1);
}
}
}
return *max_element(dp.begin(), dp.end());
}
};