#300.最长递增子序列
自己想了20min没想出来。但没关系因为没接触过该题型。我想不出来的点就是,如果i-1的最后一个不要的话,我怎么找到上一个结束点。解决方案是:再搞一个循环,一个个找(下面的 j )
下面是随想录的思路:
1. 本题dp定义非常重要:dp[i]表示i之前包括i的以nums[i]结尾的最长递增子序列的长度
每次结尾是固定的。不然新的nums不知道去和谁比较。
2. 对于每个新考虑的nums[i] ,我们从0开始找 i 之前的,谁比nums数值小,就可以考虑进来, nums[j] 作为结尾的sub
for(int i=1;i<nums.size();i++){
for(int j=0;j<i;j++){
if(nums[i]>nums[j]) dp[i]=max(dp[i],dp[j]+1);
}
res=max(res,dp[i]);
}
注意这里不是要dp[i] 与 dp[j] + 1进行比较,而是我们要取dp[j] + 1的最大值。
3. 初始化记得为1,而不是0 (只有一个char是1呀)
4. 遍历顺序没有特别的
int lengthOfLIS(vector<int>& nums) {
if(nums.size()==1) return 1;
int res=0;
vector<int> dp(nums.size(),1);
for(int i=1;i<nums.size();i++){
for(int j=0;j<i;j++){
if(nums[i]>nums[j]) dp[i]=max(dp[i],dp[j]+1);
}
res=max(res,dp[i]);
}
return res;
}
#674. 最长连续递增序列 easy
贪心 只要是连续的都很好做
int findLengthOfLCIS(vector<int>& nums) {
int res=1;
int sum=1;
for(int i=1;i<nums.size();i++){
if(nums[i]<=nums[i-1]) sum=1;
else sum++;
res=max(res,sum);
}
return res;
}
dp 跟上一个非连续的区别是,只用查i-1而不是 0 ~ i-1
int findLengthOfLCIS(vector<int>& nums) {
int res=1;
vector<int> dp(nums.size(),1);
for(int i=1;i<nums.size();i++){
if(nums[i]>nums[i-1]) dp[i]=max(dp[i],dp[i-1]+1);
res=max(res,dp[i]);
}
return res;
}
#718. 最长重复子数组 经典
区分一下 子数组 subarray 连续 和 子序列 subsequence 可以非连续
一开始以为这题是可以非连续,所以做错了。1143.最长公共子序列 这道就是 可以非连续的
本题思路(随想录):
2. 递推公式:当A[i - 1] 和B[j - 1]相等的时候,dp[i][j] = dp[i - 1][j - 1] + 1; 不然就set 0 (但是初始化已经是0了,所以不用做)
3. 4. 遍历顺序 正常
所以,代码1: dp[i][j] 代表 以 A [i -1] 和 B[j -1] 结尾的两个subarray的,不用做特别的初始化了,两层for都要从1 开始,因为0 那两条没意义,result也不在里面找。dp 大小要到size+1
int findLength(vector<int>& nums1, vector<int>& nums2) {
//need to be continuous
int m = nums1.size();
int n = nums2.size();
vector<vector<int>> dp(m+1,vector<int>(n+1,0));
int max_length = 0;
for(int i=1; i<=m; i++){
for(int j=1; j<=n; j++){
if(nums1[i-1]==nums2[j-1]){
dp[i][j] = dp[i-1][j-1] + 1;
max_length = max(max_length, dp[i][j]);
}
// else dp[i][j] = 0;
// not necessary as dp is initially filled with 0
}
}
return max_length;
}
代码2:改成用滚动数组。记得滚动数组想要不重复计算,内层for loop都要从后往前遍历
而且else情况也要赋值了,因为原来的default值被前面几层覆盖了
int findLength(vector<int>& A, vector<int>& B) {
vector<int> dp(vector<int>(B.size() + 1, 0));
int result = 0;
for (int i = 1; i <= A.size(); i++) {
for (int j = B.size(); j > 0; j--) {
if (A[i - 1] == B[j - 1]) {
dp[j] = dp[j - 1] + 1;
} else dp[j] = 0; // 注意这里不相等的时候要有赋0的操作
if (dp[j] > result) result = dp[j];
}
}
return result;
}
代码三:dp含义更intuitive的:dp[i][j] 代表 以 A [i ] 和 B[j 结尾的两个subarray的
第一列和第一行就需要单独初始化。但是后面两层for loop里面,ij都要从0开始,不然会漏掉一些收集result结果。
int findLength(vector<int>& nums1, vector<int>& nums2) {
vector<vector<int>> dp (nums1.size() + 1, vector<int>(nums2.size() + 1, 0));
int result = 0;
// 要对第一行,第一列经行初始化
for (int i = 0; i < nums1.size(); i++) if (nums1[i] == nums2[0]) dp[i][0] = 1;
for (int j = 0; j < nums2.size(); j++) if (nums1[0] == nums2[j]) dp[0][j] = 1;
for (int i = 0; i < nums1.size(); i++) {
for (int j = 0; j < nums2.size(); j++) {
if (nums1[i] == nums2[j] && i > 0 && j > 0) { // 防止 i-1 出现负数
dp[i][j] = dp[i - 1][j - 1] + 1;
}
if (dp[i][j] > result) result = dp[i][j];
}
}
return result;
}