代码随想录打卡—day48—【打家劫舍】— 8.31 打家劫舍系列

1 198. 打家劫舍

198. 打家劫舍

当时自己写,AC代码:

class Solution {
public:
    int dp[120]; // 从左往右偷  偷到第i个房子(不包含本房子)时候已经赚了的最多钱
    /*
        dp[i] = max(dp[i-1] + 0,dp[i-2]+nunms[i-2])

        dp[0] = 0
        dp[1] = 0

        升序

        模拟 样例2=== 0 0 2 7 11
    */
    int rob(vector<int>& nums) 
    {
        dp[0] = 0;
        dp[1] = 0;
        if(nums.size() == 1)return nums[0];

        int i = 2;
        for(; i < nums.size();i++)
            dp[i] = max(dp[i-1] + 0,dp[i-2]+nums[i-2]);
        
        return max(dp[i-1] + nums[i - 1],dp[i-2]+nums[i-2]);  // 这里的return 和状态转移方程不太一样
    }
};

2 213. 打家劫舍 II(打家劫舍的环形版)

213. 打家劫舍 II

一开始我的做法是在假设一个取不取,好像这样会决定隔壁的。但是题解换个角度看问题:

        (1)假装没有首元素 考虑(考虑而不是决定)后面的元素来一遍普通版打家劫舍

        (2)假装没有尾元素 考虑前面的元素来一遍普通版打家劫舍

学了题解的思想,AC代码:

class Solution {
public:
    /*
        问题1:哪个开始 随机or最大值
        最大值是不是必取?不是 所以随机选一个开始 假定是1
    */
    int dp[110];  // 偷到i房子时候最大的钱数
    /*  
        我一开始的思路——
        dp[j] = max(dp[j - 2] + nums[j],dp[j-1])
                    取                   不取
                nums.size()-1 取 
        dp[0] = 0; dp[1] = nums[1];
                nums.size()-1 不取
        dp[0] = nums[0];  dp[1] = dp[0];

        分类i++
        模拟——
    */
    /*
        上述我的假设 假定了一些格子取或者不取 然后就好像决定临近格子选择情况
        这样会把自己绕进去,不好分类讨论
        看了题解:
        (1)假装没有首元素 考虑(考虑而不是决定)后面的元素来一遍普通版打家劫舍
        (2)假装没有尾元素 考虑前面的元素来一遍普通版打家劫舍
        dp[j] = max(dp[j - 2] + nums[j],dp[j-1])

        头元素
        dp[0] = nums[0]
        头元素后一个元素
        dp[1] = max(nums[0],nums[1])

    */
    int rob(vector<int>& nums) 
    {
        if(nums.size() == 1)return nums[0];
        if(nums.size() == 2)return max(nums[0],nums[1]);

        int ans1 = normalrob(nums,0,nums.size() - 2);

        int ans2 = normalrob(nums,1,nums.size() - 1);
        return max(ans1,ans2);
    }

    int normalrob(vector<int>& nums,int l,int r)
    {
        dp[l] = nums[l];
        dp[l + 1] = max(nums[l],nums[l+1]);
        for(int i = l + 2; i <= r; i++) dp[i] = 0;

        for(int i = l + 2; i <= r; i++)
            dp[i] = max(dp[i - 2] + nums[i],dp[i-1]);

        return dp[r];
    }
};

3 337. 打家劫舍 III(打家劫舍的树形版)

337. 打家劫舍 III

第一次做,难想到一个两个元素的数组构成的dp数组,看了题解详见注释,AC代码:

/**
 * 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 dp[10010]; // dp[i] 表示偷到节点i(考虑节点i)时候的最大钱数
    /*
        想了三十秒 想不出后看题解。
        树形dp 可以不用一个死的dp数组 可以用动态的递归函数返回数组作为状态转移的容器
    */

    // 函数返回值是dp数组 下标为0表示当前节点偷时候的最大钱数
    // 下标为1表示当前节点不偷时候的最大钱数
    vector<int> dfs(TreeNode* root)
    {
        if(root == nullptr)return {0,0};
        vector<int> left = dfs(root->left);
        vector<int> right = dfs(root->right);

        // 偷当前节点
        int val1 = root->val + left[1] + right[1];
        // 不偷当前节点 那么左儿子偷和不偷都行 右儿子也是
        int val2 = max(left[0],left[1]) + max(right[0],right[1]);

        return {val1,val2};
    }
    int rob(TreeNode* root) {
        auto t = dfs(root);
        return max(t[0],t[1]);
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值