子序列
300.
dp[i]:以nums[i]为结尾的最长连续子序列的长度
dp[i]=max(dp[j]+1,dp[i]);
默认初始值为1,至少本身是的。dp[0]=1;
i从1开始,j要从0开始遍历到i-1,不断更替dp[j]的数值。
nums[i]>nums[j]的时候更替dp[i],
结果不一定存在dp[end],需要遍历取到最大值。
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
if(nums.size()<=1) return nums.size();
vector<int> dp(nums.size(),1);
int result = 0;
for(int i=1;i<nums.size();i++){
for(int j=0;j<i;j++){
if(nums[j]<nums[i]) dp[i]=max(dp[i],dp[j]+1);
}
if (dp[i] > result) result = dp[i]; // 取长的子序列
}
return result;
}
};
674.最长连续递增子序列
class Solution {
public:
int findLengthOfLCIS(vector<int>& nums) {
//dp[i]:以下标i为结尾的连续递增的子序列长度为dp[i]。
if(nums.size()==0) return 0;
int result =1;
vector<int> dp(nums.size(),1);
for(int i=1;i<nums.size();i++){
if(nums[i]>nums[i-1]){
dp[i]=dp[i-1]+1;
}
if(dp[i]>result) result=dp[i];
}
return result;
}
};
337.打家劫舍3
最优解集中在根节点上,二叉树和动态规划结合。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int rob(TreeNode* root) {
//在树上面进行状态转移
vector<int> result = robTree(root);
return max(result[0],result[1]);
}
//偷与不偷两个状态所能得到的钱,
//dp数组(dp table)以及下标的含义:下标为0记录不偷该节点所得到的的最大金钱,下标为1记录偷该节点所得到的的最大金钱。
vector<int> robTree(TreeNode* cur){
//遇到空节点,偷与不偷都是0
if(cur ==NULL) return vector<int>{0,0};
//后序遍历
//递归左节点,得到偷与不偷的最大金钱
//递归右节点,得到偷与不偷的最大金钱
//下标0 不偷;下标1:偷
vector<int>left = robTree(cur->left);
vector<int>right = robTree(cur->right);
//中:偷当前节点,那么左右孩子就不能偷;不偷当前节点,那么左右孩子就可以偷,至于到底偷不偷一定是选一个最大的
//偷
int val1 = cur->val + left[0] + right[0];
//不偷
int val2 = max(left[0], left[1]) + max(right[0], right[1]);
//返回当前节点的偷与不偷状态
return {val2, val1};
}
};