【Day47】代码随想录之动态规划part9——打家劫舍、打家劫舍II、打家劫舍III

本文详细解析了LeetCode中的打家劫舍系列问题(198,213,337),涉及动态规划方法,包括dp数组的定义、递推公式、初始化、遍历顺序以及特殊情况的处理。重点介绍了如何将连续和非连续数组问题转化为动态规划问题求解。
摘要由CSDN通过智能技术生成

今天晚上补动态规划中的打家劫舍的系列的问题,不算难,一口气拿下。

今日任务:

  • 198.打家劫舍
  • 213.打家劫舍II
  • 337.打家劫舍III

题目一:198.打家劫舍

Leetcode题目:【198.打家劫舍】

在这里插入图片描述
当前房间的偷和不偷,会影响后面的选择,因此可以将其转化为一个动规的问题。

(1)确定dp数组含义:考虑下标i(包含i),他能偷的最大金额为dp[i],最后就是dp[nums.size()-1]
(2)我们的递推公式:
偷i:dp[i] = dp[i-2] + nums[i]
不偷i:dp[i] = dp[i-1]
dp[i] = max(dp[i-1], dp[i-2] + nums[i]);
(3)初始化:
dp[0] = nums[0];
dp[1] = max(nums[0], nums[1]);
(4)遍历顺序:
从前往后依次遍历就可以了。
(5)打印dp数组。

此题的注意点为:前面需要判断如果是0或者1的情况。

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

题目二:213.打家劫舍II

Leetcode题目:【213.打家劫舍II】

在这里插入图片描述
这个与上面那个题就是数组成环了。如果连成环的话,应该如何思考:
这样可以分为三种情况:
(1)不选首元素也不选尾元素;
(2)考虑首元素,不考虑尾元素;
(3)考虑尾元素,不考虑首元素。
在这里插入图片描述
这个就是第二种情况是包含情况一的,情况三也是包含情况一的。因此只需要比较情况二和情况三的最大值,情况二和情况三都是一个线性表,因此就是利用两次相同的函数,然后比较谁大,最后就返回谁的值。

再回到上面的非环的数组,按照递归五部曲的分析如下:
(1)确定dp数组的含义,dp[i]表示考虑到下标i,可以偷到的最大金额数为dp[i];
(2)递推公式:

偷:dp[i] = dp[i-2] + nums[i];
不偷:dp[i] = dp[i-1]
dp[i] = max(dp[i-1], dp[i-2] + nums[i])

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

(4)遍历顺序:从小到大即可。
(5)打印dp数组;

注意点:函数的构造

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

    int rob(vector<int>& nums) {
        if(nums.size() == 0) return 0;
        if(nums.size() == 1) return nums[0];
        int tradition2 = maxValue(nums, 0, nums.size()-2);
        int tradition3 = maxValue(nums, 1, nums.size()-1);
        return max(tradition2, tradition3);
    }
};

题目三:337.打家劫舍III(太难了,就简单欣赏下吧)

Leetcode题目:【337.打家劫舍III】

在这里插入图片描述
此题是树形dp的一个入门题目,递归三部曲 + 动规五部曲。
一维的dp数组,dp[0]表示不偷当前节点,获得的最大金钱;dp[1]表示偷,获得的最大金钱。
二叉树采用后序遍历(左、右、中)。

可以理解,但是不好写。

仅简单欣赏下代码:

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};
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值