day48 ● 198.打家劫舍 ● 213.打家劫舍II ● 337.打家劫舍III

一遍过。

当前房屋偷与不偷取决于 前一个房屋和前两个房屋是否被偷了。所以这里就更感觉到,当前状态和前面状态会有一种依赖关系,那么这种依赖关系都是动规的递推公式。

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

 题解的递推公示少了一个维度,

决定dp[i]的因素就是第i房间偷还是不偷。

如果偷第i房间,那么dp[i] = dp[i - 2] + nums[i] ,即:第i-1房一定是不考虑的,找出 下标i-2(包括i-2)以内的房屋,最多可以偷窃的金额为dp[i-2] 加上第i房间偷到的钱。

如果不偷第i房间,那么dp[i] = dp[i - 1],即考 虑i-1房,(注意这里是考虑,并不是一定要偷i-1房,这是很多同学容易混淆的点

然后dp[i]取最大值,即dp[i] = max(dp[i - 2] + nums[i], dp[i - 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());dp[0] = nums[0];dp[1] = max(nums[0], nums[1]);for (int i = 2; i < nums.size(); i++) {dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);}return dp[nums.size() - 1];}
};

 

首尾元素大概知道要分为是否考虑末尾元素,考虑了末尾元素的情况对应选取第二个到最后一个元素,没有题解方法清晰。看了题解。

 可以分为三种情况,

  • 情况一:考虑不包含首尾元素;
  • 情况二:考虑包含首元素,不包含尾元素;
  • 情况二:考虑包含首元素,不包含尾元素;(其实情况二和情况三包括了情况一)
class Solution {
public:int rob(vector<int>& nums) {if(nums.size()==0) return 0;if(nums.size()==1) return nums[0];if(nums.size()==2) return max(nums[0],nums[1]);return max(robrange(nums,0,nums.size()-2),robrange(nums,1,nums.size()-1));}int robrange(vector<int>& nums,int start,int end){if(start==end) return nums[end];vector<int> dp(nums.size()+1,0);dp[start]=nums[start];dp[start+1]=max(nums[start],nums[start+1]);for(int i=start+2;i<=end;i++){dp[i]=max(dp[i-2]+nums[i],dp[i-1]);}return dp[end];}
};

 

 我一开始写的递归版本,超出时间限制了。原因是在算左边的孩子节点时,和算他的左右孩子节点会重复(各自会递归算一次)。

/*** 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 rob(TreeNode* root) {int tmpl=0,tmpr=0 ;int tmpll=0,tmplr=0,tmprl=0,tmprr=0;if(root->left){tmpl=rob(root->left);if(root->left->left){tmpll=rob(root->left->left);}if(root->left->right){tmplr=rob(root->left->right);}}if(root->right){tmpr=rob(root->right);if(root->right->left){tmprl=rob(root->right->left);}if(root->right->right){tmprr=rob(root->right->right);}}return max(root->val+tmpll+tmplr+tmprl+tmprr,tmpl+tmpr);}
};

看了题解:对于树的话,首先就要想到遍历方式,前中后序(深度优先搜索)还是层序遍历(广度优先搜索)。本题一定是要后序遍历,因为通过递归函数的返回值来做下一步计算

要注意特判断

if (root == NULL) return 0;
if (root->left == NULL && root->right == NULL) return root->val;

 记忆化搜索:要会使用unordered_map

/*** 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:unordered_map<TreeNode*, int> mp;int rob(TreeNode* root) {if(root==NULL) return 0;if(root->left==NULL&&root->right==NULL) return root->val;int tmpl=0,tmpr=0 ;int tmpll=0,tmplr=0,tmprl=0,tmprr=0;if(mp[root]) return mp[root];if(root->left){tmpl=rob(root->left);mp[root->left]=tmpl;if(root->left->left){tmpll=rob(root->left->left);mp[root->left->left]=tmpll;}if(root->left->right){tmplr=rob(root->left->right);mp[root->left->right]=tmplr;}}if(root->right){tmpr=rob(root->right);mp[root->right]=tmpr;if(root->right->left){tmprl=rob(root->right->left);mp[root->right->left]=tmprl;}if(root->right->right){tmprr=rob(root->right->right);mp[root->right->right]=tmprr;}}return max(root->val+tmpll+tmplr+tmprl+tmprr,tmpl+tmpr);}
};

动态规划方法:

 对当前节点是偷与不偷两种状态:dp数组(dp table)以及下标的含义:下标为0记录不偷该节点所得到的的最大金钱,下标为1记录偷该节点所得到的的最大金钱。

如果是偷当前节点,那么左右孩子就不能偷,val1 = cur->val + left[0] + right[0]; (如果对下标含义不理解就再回顾一下dp数组的含义

如果不偷当前节点,那么左右孩子就可以偷,至于到底偷不偷一定是选一个最大的,所以:val2 = max(left[0], left[1]) + max(right[0], right[1]);

/*** 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 rob(TreeNode* root) {vector<int> res=robrange(root);return max(res[0],res[1]);}vector<int> robrange(TreeNode* root){if(root==NULL) return vector<int>{0,0};vector<int> left=robrange(root->left);vector<int> right=robrange(root->right);return vector<int>{max(left[0],left[1])+max(right[0],right[1]),root->val+left[0]+right[0]};}
};

上题是树形dp入门。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/502019.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【矩阵】【方向】【素数】3044 出现频率最高的素数

作者推荐 动态规划的时间复杂度优化 本文涉及知识点 素数 矩阵 方向 LeetCode 3044 出现频率最高的素数 给你一个大小为 m x n 、下标从 0 开始的二维矩阵 mat 。在每个单元格&#xff0c;你可以按以下方式生成数字&#xff1a; 最多有 8 条路径可以选择&#xff1a;东&am…

C/C++ 迷宫游戏

游戏介绍 这个迷宫探险游戏有以下功能&#xff1a; 探险&#xff1a;选择该选项后&#xff0c;玩家会进入地下迷宫进行探险。在随机事件中&#xff0c;可能会遇到陷阱、发现金币或者什么都没有发生。陷阱会使玩家失去一定的生命值&#xff0c;金币可以增加玩家的金币数量。 休…

springboot yml方式多环境切换 dev,test,prod环境

第一步,创建对应的yml文件 application.yml application-dev.yml application-prod.yml application-test.yml 第二步,在application.yml中指定对一个的 环境文件 spring:profiles:active: prod记住 只用指定 dev,test,prod 就可以了 第三步 在不同的配置文件,配置不一样…

边缘计算网关在机场生产中的应用-天拓四方

随着工业4.0的推进&#xff0c;物联网&#xff08;IoT&#xff09;技术在各个工业领域中的应用日益广泛。特别是在机床行业&#xff0c;物联网技术的引入不仅提高了生产效率&#xff0c;还实现了对机床设备的实时监控和远程维护。在这一背景下&#xff0c;边缘计算网关的角色愈…

LeetCode刷题--- 乘积为正数的最长子数组长度

个人主页&#xff1a;元清加油_【C】,【C语言】,【数据结构与算法】-CSDN博客 个人专栏 力扣递归算法题 http://t.csdnimg.cn/yUl2I 【C】 ​​​​​​http://t.csdnimg.cn/6AbpV 数据结构与算法 ​​​http://t.csdnimg.cn/hKh2l 前言&#xff1a;这个专栏主要讲述动…

GEE:计算NDVI时间序列和谐波拟合曲线之间的残差时间序列

作者:CSDN @ _养乐多_ 本文将介绍在谷歌地球引擎(Google Earth Engine)使用 Landsat 时间序列数据数据进行时间序列谐波(harmonic)拟合建模,并对模型的残差(residual)序列(计算NDVI时间序列和谐波拟合曲线之间的残差时间序列)进行分析。具体流程为使用Landsat计算ND…

【leetcode】环形链表✚环形链表II

大家好&#xff0c;我是苏貝&#xff0c;本篇博客带大家刷题&#xff0c;如果你觉得我写的还不错的话&#xff0c;可以给我一个赞&#x1f44d;吗&#xff0c;感谢❤️ 目录 1.环形链表解题拓展&#xff1a; 2.环形链表II 1.环形链表 点击查看题目 解题 思路: bool hasCycle…

C++基于多设计模式下的同步异步日志系统day2

&#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;C基于多设计模式下的同步&异步日志系统 &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 主要内容实现了日志代码设计的实…

11.网络游戏逆向分析与漏洞攻防-游戏网络架构逆向分析-接管游戏接收网络数据包的操作

内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;接管游戏发送数据的操作 码云地址&#xff08;master 分支&#xff09;&#xff1a;https://gitee.com/dye_your_fingers/titan 码云版本号&#xff1a;8256eb53e8c16281bc1a29cb8d26d352bb5bbf4c 代…

软件测试最重要的事之【编写用例】

软件测试用例得出软件测试用例的内容&#xff0c;其次&#xff0c;按照软件测试写作方法&#xff0c;落实到文档中&#xff0c;两者是形式和内容的关系&#xff0c;好的测试用例不仅方便自己和别人查看&#xff0c;而且能帮助设计的时候考虑的更周。 一个好的测试用例必须包含…

【HTML】HTML基础系列文章小小总结,运用标签写出网页!

宇宙级声明&#xff01;这次只运用了一些基础标签&#xff0c;希望不要丑到大家~ 目录 效果预览&#xff1a;​编辑​编辑 点击百度百科 点击图片 点击下载 标签说明 源代码 效果预览&#xff1a; 点击百度百科 点击图片 点击下载 标签说明 标题 加粗文字 下划线 换行 分…

IO-DAY2

用发write、fread将一张随意图片修改成德国国旗 #include<stdio.h> #include<string.h> #include<stdlib.h> #include<unistd.h> int main(int argc, char *argv[]) {FILE* fpfopen("./122.bmp","r");int w 0,h 0;fseek(fp,18,…