代码随想录算法训练营第四十五天 | 打家劫舍

198.打家劫舍

题目链接 文章讲解 视频讲解

  • dp[j]: 表示投到第j家最多能偷dp[j]的钱
  • 递推公式: dp[j] = max(dp[j-2] + nums[j], dp[j-1])
  • 初始化:dp[0] = nums[0], dp[1] = max(dp[0], dp[1])
  • 遍历顺序:从小到大
  • 打印dp数组
class Solution {
public:
    int rob(vector<int>& nums) {
        // dp[j]: 表示偷第j家最多能偷多少
        int n = nums.size();
        vector<int> dp(n);
        if(n == 0) return 0;
        if(n == 1) return nums[0];
        
        // 递推公式: dp[j] = dp[j - 2] + nums[j]

        // 初始化:
        dp[0] = nums[0];
        dp[1] = max(nums[0], nums[1]);

        for(int j = 2; j < n; ++j) {
            dp[j] = max(dp[j - 2] + nums[j], dp[j-1]);
        }

        for(int val : dp) cout << val << " ";

        return dp[n - 1];
    }
};

213.打家劫舍II

题目链接 文章讲解 视频讲解

思路: 首元素和尾元素只能有一个,所以分两种情况,加入首元素和加入尾元素分别求,然后取最大的

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

        return max(robRange(nums, 0, n -1), robRange(nums, 1, n));
    }

    int robRange(vector<int>& nums, int start, int end) {
        vector<int> dp(end);
        dp[start] = nums[start];
        dp[start + 1] = max(nums[start], nums[start + 1]);
        for(int j = start + 2; j < end; ++j) {
            dp[j] = max(dp[j - 2] + nums[j], dp[j-1]);
        }
        return dp[end-1];
    }
};

打家劫舍III

题目链接 文章讲解 视频讲解

动规五部曲:

  • dp[0] dp[1]分别表示不偷当前节点得到的最大值和偷当前节点的最大值
  • 递推公式:
    • 偷当前节点: dp[0] = cur->val + left_dp[0] + right_dp[0],如果偷了当前节点,那么左右孩子就不可以偷了
    • 不偷当前节点:dp[1] = max(left_dp[0], left[1]) + max(right_dp[0], right_dp[1]) 分别计算左右孩子偷与不偷的最大值相加即可
  • 初始话:初始化为任意值都可以因为dp值不以来当前dp数组,而只依赖于左右孩子的dp数组
  • 遍历顺序:由递推公式可知,要计算当前dp值需要先获取左右孩子的dp值,所以应用后序遍历
class Solution {
public:
    int rob(TreeNode* root) {
        // dp[0]表示不偷当前节点的最大值,dp[1]表示偷当前节点的最大值
        vector<int> dp = traversal(root);
        return max(dp[0], dp[1]);
    }

    vector<int> traversal(TreeNode* root) {
        if(root == nullptr) return {0, 0};

        vector<int> left_dp = traversal(root->left);
        vector<int> right_dp = traversal(root->right);
        int val1 = root->val + left_dp[0] + right_dp[0];
        int val2 = max(left_dp[0], left_dp[1]) + max(right_dp[0], right_dp[1]);
        return {val2, val1};
    }
};
posted @ 2024-07-02 22:30  深蓝von  阅读(3)  评论(0编辑  收藏  举报