当前位置: 首页 > news >正文

【LeetCode-337】打家劫舍III(动态规划)

目录

题目描述

解法1:动态规划

代码实现


题目链接

题目描述

在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。

计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。

解法1:动态规划

这道题目算是树形dp的入门题目,因为是在树上进行状态转移,我们在讲解二叉树的时候说过递归三部曲,那么下面我以递归三部曲为框架,其中融合动规五部曲的内容来进行讲解

  1. 确定递归函数的参数和返回值

这里我们要求一个节点 偷与不偷的两个状态所得到的金钱,那么返回值就是一个长度为2的数组。

参数为当前节点,代码如下:

vector<int> robTree(TreeNode* cur) {

其实这里的返回数组就是dp数组。

所以dp数组(dp table)以及下标的含义:下标为0记录不偷该节点所得到的的最大金钱,下标为1记录偷该节点所得到的的最大金钱。

所以本题dp数组就是一个长度为2的数组!

那么有同学可能疑惑,长度为2的数组怎么标记树中每个节点的状态呢?

别忘了在递归的过程中,系统栈会保存每一层递归的参数

如果还不理解的话,就接着往下看,看到代码就理解了哈。

  1. 确定终止条件

在遍历的过程中,如果遇到空节点的话,很明显,无论偷还是不偷都是0,所以就返回

if (cur == NULL) return vector<int>{0, 0};

这也相当于dp数组的初始化

  1. 确定遍历顺序

首先明确的是使用后序遍历。 因为要通过递归函数的返回值来做下一步计算。

通过递归左节点,得到左节点偷与不偷的金钱。

通过递归右节点,得到右节点偷与不偷的金钱。

代码如下:

// 下标0:不偷,下标1:偷
vector<int> left = robTree(cur->left); // 左
vector<int> right = robTree(cur->right); // 右
// 中
  1. 确定单层递归的逻辑

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

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

最后当前节点的状态就是{val2, val1}; 即:{不偷当前节点得到的最大金钱,偷当前节点得到的最大金钱}

代码如下:

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};

代码实现
class Solution {public int rob(TreeNode root) {if (root.left == null && root.right == null) return root.val;int[] dp = dfs(root);return Math.max(dp[0], dp[1]);}
​public int[] dfs(TreeNode root) {int[] leafArr = new int[2];if (root == null) return leafArr;int[] left = dfs(root.left);int[] right = dfs(root.right);
​int[] dp = new int[2];dp[0] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);dp[1] = root.val + left[0] + right[0];return dp;
​}
}

相关文章:

  • vivado FSM Components
  • 云HIS系统源码,基于云计算技术的B/S架构的云HIS系统,二甲医院信息管理系统
  • 【Ubuntu】Anaconda的安装和使用
  • etcd: mac 环境部署
  • Windows+Yolo3-darknet训练自己数据集并测试
  • 【0265】postmaster守护进程入口
  • 学习大数据所需的java基础(5)
  • 【PHP设计模式03】抽象工厂模式
  • 面试经典150题——快乐数
  • 大数据-数据可视化-环境部署vue+echarts+显示案例
  • uniapp:APP端webview拦截H5页面跳转,华为市场发布需要限制webview的H5页面跳转
  • 【Elasticsearch专栏 12】深入探索:Elasticsearch使用索引生命周期管理(ILM)自动化删除旧数据
  • 安卓OpenGL添加水印并录制(二)---抖音录制原理
  • 测试环境搭建整套大数据系统(六:搭建sqoop)
  • 快速搭建ARM64实验平台(QEMU虚拟机+Debian)
  • Angularjs之国际化
  • centos安装java运行环境jdk+tomcat
  • electron原来这么简单----打包你的react、VUE桌面应用程序
  • maya建模与骨骼动画快速实现人工鱼
  • Mysql数据库的条件查询语句
  • SQLServer插入数据
  • vue-router的history模式发布配置
  • windows-nginx-https-本地配置
  • 读懂package.json -- 依赖管理
  • 对JS继承的一点思考
  • 工作中总结前端开发流程--vue项目
  • 浅谈Kotlin实战篇之自定义View图片圆角简单应用(一)
  • 设计模式(12)迭代器模式(讲解+应用)
  • 微信小程序设置上一页数据
  • 系统认识JavaScript正则表达式
  • ​​​​​​​sokit v1.3抓手机应用socket数据包: Socket是传输控制层协议,WebSocket是应用层协议。
  • !!【OpenCV学习】计算两幅图像的重叠区域
  • # Swust 12th acm 邀请赛# [ A ] A+B problem [题解]
  • (2)nginx 安装、启停
  • (poj1.2.1)1970(筛选法模拟)
  • (Redis使用系列) SpringBoot中Redis的RedisConfig 二
  • (带教程)商业版SEO关键词按天计费系统:关键词排名优化、代理服务、手机自适应及搭建教程
  • (多级缓存)多级缓存
  • (二)WCF的Binding模型
  • (附源码)springboot课程在线考试系统 毕业设计 655127
  • (附源码)ssm考试题库管理系统 毕业设计 069043
  • (接口自动化)Python3操作MySQL数据库
  • (三分钟)速览传统边缘检测算子
  • (转) Android中ViewStub组件使用
  • (转)ABI是什么
  • (转)真正的中国天气api接口xml,json(求加精) ...
  • .NET 回调、接口回调、 委托
  • .NET 指南:抽象化实现的基类
  • /dev/sda2 is mounted; will not make a filesystem here!
  • /var/lib/dpkg/lock 锁定问题
  • [Apio2012]dispatching 左偏树
  • [AutoSAR 存储] 汽车智能座舱的存储需求
  • [C#]winform制作仪表盘好用的表盘控件和使用方法
  • [C#]使用PaddleInference图片旋转四种角度检测
  • [C#]手把手教你打造Socket的TCP通讯连接(一)