代码随想录算法训练营第四十七天| 动态规划

Posted by Zhuoqun on March 1, 2023

198.打家劫舍

终于没借助任何提示,自己写出来了。

class Solution {
public:
    int rob(vector<int>& nums) {
        vector<int> dp (nums.size()+1,0);
        dp[0] = 0;
        dp[1] = nums[0];

        for(int i=2; i<=nums.size(); i++){
            dp[i] = max(nums[i-1]+dp[i-2],dp[i-1]);
        }

        return dp[nums.size()];
    }
};

213.打家劫舍II

这道题我想的思路是给用了首元素的组合都做上记号。如果最后一个元素用了首元素,那么就取dp倒数第二位的值。但这个方法经过提交后,发现是有错误的。可能有些逻辑上错误。

class Solution {
public:
    int rob(vector<int>& nums) {
        if(nums.size() == 1){
            return nums[0];
        }
        vector<int> dp(nums.size(),0);
        vector<bool> stat(nums.size(),false);
        stat[0] = true;
        dp[0] = nums[0];

        if(nums[1] < nums[0]){
            stat[1] = true;
            dp[1] = nums[0];
        }
        else{
            dp[1] = nums[1];
        }

        for(int i=2;i<nums.size(); i++){
            if(dp[i-2]+nums[i] > dp[i-1]){
                dp[i] = dp[i-2]+nums[i];
                stat[i] = stat[i-2];
            }
            else{
                dp[i] = dp[i-1];
                stat[i] = stat[i-1];
            }
        }
        

        if(stat[nums.size()-1] && nums.size()>2){
            return max(dp[nums.size()-1]-nums[0],dp[nums.size()-2]);
        }
        else{
            return dp[nums.size()-1];
        }
    };
};

下面的是我根据Carl的文字讲解理解了,自己写出来的。

做动态规划题的时候,总会遇到访问不正确内存的时候,原因就是我的for loop里的边界设的不对。就像是这次,我就是忘了把for loop里的起始点设为start+2,因为我们已经初始化过前两个值,所以就没必要从前两个值开始遍历,遍历的话反而会访问错误的内存。

class Solution {
public:
    vector<int> robhelper(vector<int>& nums,int start, int end){
        cout<<start<<" "<<end<<endl;
        vector<int> res(nums.size(),0);
        res[start] = nums[start];
        res[start+1] = max(nums[start],nums[start+1]);
        for(int i=start+2; i<end; i++){
            res[i] = max(res[i-2]+nums[i],res[i-1]);
        }
        return res;
    }
    int rob(vector<int>& nums) {
        if(nums.size() == 1){
            return nums[0];
        }
        if(nums.size() == 2){
            return max(nums[0],nums[1]);
        }
        vector<int> no_first = robhelper(nums,1,nums.size());
        vector<int> no_last = robhelper(nums,0,nums.size()-1);

        return max(no_first[nums.size()-1],no_last[nums.size()-2]);
    }
};

337.打家劫舍III

把这两个融合到了一起,可真是够难的。我自己没写出来。好绕啊。

class Solution {
public:
    int rob(TreeNode* root) {
        vector<int> result = robTree(root);
        return max(result[0], result[1]);
    }
    // 长度为2的数组,0:不偷,1:偷
    vector<int> robTree(TreeNode* cur) {
        if (cur == NULL) return vector<int>{0, 0};
        vector<int> left = robTree(cur->left);
        vector<int> right = robTree(cur->right);
        // 偷cur,那么就不能偷左右节点。
        int val1 = cur->val + left[0] + right[0];
        // 不偷cur,那么可以偷也可以不偷左右节点,则取较大的情况
        int val2 = max(left[0], left[1]) + max(right[0], right[1]);
        return {val2, val1};
    }
};