Day39| 198.打家劫舍、213.打家劫舍II、337.打家劫舍 III

2025-08-16

198.打家劫舍

题目链接:198.打家劫舍
文档讲解:代码随想录
状态:轻松AC

思路

本题的思路:考虑一个房子要不要偷时不能单凭自己确定需要看之前的状态,这就是动态规划。

简单的五部曲,记住要考虑周全(尤其是遍历起点、顺序与初始化问题)。

题解

class Solution {
public:
    int rob(vector<int>& nums) {
        vector<int> dp(nums.size(),0);
        dp[0] = nums[0];
        if(nums.size()>1)dp[1] = max(nums[0],nums[1]);
        for(int i = 2;i<nums.size();i++)
        {
            dp[i] = max(dp[i-1],nums[i]+dp[i-2]);
        }
        return dp[nums.size()-1];    
    }
};

213.打家劫舍II

题目链接:213.打家劫舍II
文档讲解:代码随想录
状态:不会,对于首尾相连没有思路,最简单的没想到

思路

与上一题的区别在于首尾相连,两者不能同时取,我的思考方式一直纠结于如何在内部解决环问题。

事实上,内部解决不了,还真得跳出来用笨方法思考。

最优情况仅可能且若有一定存在三种情况的一种,如下:

  • 情况一:考虑不包含首尾元素

chart

  • 情况二:考虑包含首元素,不包含尾元素

chart

  • 情况三:考虑包含尾元素,不包含首元素

chart

两者不能同时取->首随意尾不取+首不取尾随意,三种即可解题,再思考即可化简。

题解

class Solution {
public:
    int res(vector<int>& nums)
    {
        vector<int> dp(nums.size(),0);
        dp[0] = nums[0];
        if(nums.size()>1)dp[1] = max(nums[0],nums[1]);
        for(int i = 2;i<nums.size();i++)
        {
            dp[i] = max(dp[i-1],nums[i]+dp[i-2]);
        }
        return dp[nums.size()-1];
        
    }
    int rob(vector<int>& nums) {
        if(nums.size() == 1)return nums[0];//防止越界

        vector<int> nums1(nums.begin(),nums.end()-1);
        vector<int> nums2(nums.begin()+1,nums.end());
        int result1 = res(nums1);
        int result2 = res(nums2);
        return result1>result2?result1:result2;    
    }
};

337.打家劫舍 III

题目链接:337.打家劫舍 III
文档讲解:代码随想录
状态:知道是动规,写不出dp

思路

本题知道是动态规划,关键点是当前状态取决于之前状态的最优值+是否取值两种状态,不能简单将返回值视作单个int

将所有状态均写入dp以供后面使用,避免重复计算,这就是动态规划。

注意理解本题递归与动态规划复杂度的区别。

题解

class Solution {
public:
    //dp[0]不偷  dp[1]偷
    vector<int> robtree(TreeNode* cur)
    {
        if(cur == nullptr)return {0,0};
        //一个式子计算4次递归,其实计算一次即可,不然爆内存
        //int res1 = cur->val+robtree(cur->left)[0]+robtree(cur->right)[0];
        //int res2 = max(robtree(cur->left)[0],robtree(cur->left)[1])+max(robtree(cur->right)[0],robtree(cur->right)[1]);
        vector<int> left = robtree(cur->left);
        vector<int> right = robtree(cur->right);
        int res1 = cur->val+left[0]+right[0];
        int res2 = max(left[0],left[1])+max(right[0],right[1]);
        return {res2,res1};
    }
    int rob(TreeNode* root) {
        vector<int> result = robtree(root);
        if(result[0]>result[1])return result[0];
        else return result[1];
    }
};