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

算法第34天|动态规划:打家劫舍Ⅰ、打家劫舍Ⅱ、打家劫舍Ⅲ

今日总结:

        打家劫舍

                1、如果遇到了对dp数组的前几个值定义,在进行遍历时,要思考前几个值还需不需要遍历

                2、这道题其实没有出现,前边的题型中出现过

                        dp递推公式中出现min:在初始化的时候一定要注意普通位置要初始化为INT_MAX而不能是0.

        打家劫舍Ⅱ
                1、增加了额外条件圆形,所以分情况讨论:放首不放尾,放尾不放首,首尾都不放

                2、注意:dp[start] = max(nums[start],nums[start+1]);

        打家劫舍Ⅲ(重点复习

打家劫舍Ⅰ

题目链接:198. 打家劫舍 - 力扣(LeetCode)

代码随想录

整体思路:

        通过题目可知:

                1、影响偷窃的唯一因素就是不能偷相邻的房屋。

                2、需要在不偷窃相邻房屋的情况下偷窃最高的金额

        所以,可以将题目抽象:

                1、我偷房间i,房间i-1一定是不能被偷的,所以是房间i-2偷的最多的钱+房间i的钱,所以这道题是当前状态与之前状态有关-->动态规划问题

        动态规划五部曲确定这道题

                1、确定dp数组及下标

                        dp[i]:表示在[0,i]的房间中偷窃在不触发警报的条件下能偷窃的最大金额

                2、确定dp数组的递推公式(状态转移方程)

                        dp[i]与前边两个房间有关

                        如果要偷房间i的钱,就不能偷房间i-1,所以要计算房间i-2的最大金额

                        dp[i] = dp[i-2]+nums[i]

                        如果不偷房间i,就需要统计房间i-1的最大金额

                        dp[i] = dp[i-1]

                        所以dp递推公式:

                                dp[i] = max(dp[i-1],dp[i-2]+nums[i])

                3、确定dp数组的初始化

                        通过递推公式可知dp[i]的获取最终归结到dp[0]和dp[1]

                        dp[0]表示在房间0之前的房间中不触发警报能偷窃的最大金额

                        dp[0] = nums[0]

                        dp[1]表示在[0,1]的房间中,不触发警报(不连续偷房间)的最大金额

                        dp[1] = max(dp[0],dp[1])

                4、确定dp数组的遍历条件

                        房间从0-nums.size()

整体代码:

class Solution {
public:int rob(vector<int>& nums) {//定义dp数组vector<int>dp(nums.size(),0);//初始化if(nums.size()==0)return  0;else if(nums.size()==1) return nums[0];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)

代码随想录

整体思路:

        相较于打家劫舍Ⅰ相比,只是多了一个条件:

                现在的房屋是一个圆环形,也就是说首尾两间房不能同时都选择,最多选择一间或者都不选

                1、选择首房,一定不能选择尾房,所以钱最多从dp[nums.size()-1]中获得

                2、选择尾房,一定不能选择首房,也就是说dp数组是从dp[1]开始计算的

                3、首尾都不选择:其实已经被1、2包括了,因为1中选择首房中也不一定选择首房,需要比较怎样获得的钱最多,2中同理

                所以需要将打家劫舍Ⅰ中的内容写成函数,比较max(fun(1),fun(2))

整体代码:

class Solution {
public://定义打家劫舍函数//返回值:最大的金额int//输入值:数组、数组的起始、终止int dajiajieshe(vector<int>&nums ,int start,int end){//首先判断传入的数据是不是0或者1if(end-start==0)//说明只有一个数return nums[start];else if(end-start==1)//说明只有两个数return max(nums[start],nums[end]);//定义dp数组,大小仍旧是nums.size(),不要因为首尾不同而发生变化,将对应值填入对应的dp位置才在最后能比较vector<int>dp(nums.size(),0);//初始化dp[start] = nums[start];dp[start+1] = max(dp[start],nums[start+1]);//遍历for(int i=start+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;else if(nums.size()==1)return nums[0];int res1 =dajiajieshe(nums,0,nums.size()-2);int res2 =dajiajieshe(nums,1,nums.size()-1);return max(res1,res2);}
};

打家劫舍Ⅲ

题目链接:337. 打家劫舍 III - 力扣(LeetCode)

代码随想录

整体思路:

 //整体来说:

        1、如果我偷了一个节点,那么我就不能偷这个节点的子节点

        2、如果我不偷这个节点,那么我可以偷这个节点的子节点,也可以不偷这个节点的子节点(取最大值)

        所以当前节点的状态与下边节点的值有关-->dp;同时因为是树形结构,且需要从上到下-->后序遍历

        dp数组就是max(偷,不偷)

        当前节点的值:偷当前节点-->取下下个子节点的最大+当前节点的值

                                不偷当前节点-->取下个子节点的最大

        下下个子节点其实也存在偷与不偷的关系,所以可以对每个节点记录偷当前节点与不偷当前节点所达到的最大的值-->2位数组记录偷与不偷的值,然后后序遍历-->可以得到根节点的最大钱数max(偷,不偷)

整体代码:

/*** 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://整体来说://1、如果我偷了一个节点,那么我就不能偷这个节点的子节点//2、如果我不偷这个节点,那么我可以偷这个节点的子节点,也可以不偷这个节点的子节点(取最大值)//所以当前节点的状态与下边节点的值有关-->dp;同时因为是树形结构,且需要从上到下-->后序遍历//后序遍历,需要知道一个节点的偷的值,不偷的值://1、确定后序遍历的返回值和参数//返回值是2位数组:存储偷的钱,不偷的钱,当前的节点可以根据之前的返回值,计算对应的偷当前节点、不偷当前节点的钱,便于上边的节点计算//参数:当前节点vector<int> digui(TreeNode* root){//2、确定返回值:后序遍历需要遍历到叶子节点下的空节点返回0if(root==nullptr)return vector<int>{0,0};//3、单层递归逻辑//后序遍历,先遍历前、后vector<int> left = digui(root->left);vector<int> right = digui(root->right);//开始判断当前层偷与不偷的钱 不偷0 ,偷1//不偷当前层,可以偷下一层,也可以不偷下一层,看谁的钱多int no_cur = max(left[1],left[0])+max(right[1],right[0]);//偷当前层,就不能偷下一层,可以偷下下层int yes_cur = root->val+left[0]+right[0];//返回当前层return {no_cur,yes_cur};}int rob(TreeNode* root) {vector<int>res = digui(root);//偷不偷的钱都在res,判断偷root的多,还是不偷root的多return max(res[0],res[1]);}
};

http://www.dtcms.com/a/341371.html

相关文章:

  • 为了更强大的空间智能,如何将2D图像转换成完整、具有真实尺度和外观的3D场景?
  • (双类别检测:电动车 + 头部,再对头部分类)VS 单类别检测 + ROI 分类器 方案
  • 小迪安全v2023学习笔记(六十七讲)—— Java安全JNDI注入五大不安全组件RCE不出网
  • 2025年中高级后端开发Java岗八股文最新开源
  • 利用 PHP 爬虫获取店铺所有商品实战指南
  • Spring Boot 3.4.x 性能优化实战:用 Undertow 替换 Tomcat 全指南​
  • 自动驾驶汽车机器学习安全实用解决方案
  • 三坐标性能的创新重构,“高精度、紧凑型、高稳定性”三位一体
  • 鸿蒙中Profiler的使用
  • STM32学习笔记16-SPI硬件控制
  • MySQL 语法基础入门:从零开始掌握数据库操作
  • CoreShop微信小程序商城框架开启多租户-添加一个WPF客户端以便进行本地操作(5)
  • 读《精益数据分析》:规模化(Scale)—— 复制成功,进军新市场
  • VMware Workstation | 安装Ubuntu18.04.5
  • 波纹干涩 shader
  • 零知开源——基于STM32F103RBT6与ADXL362三轴加速度计的体感迷宫游戏设计与实现
  • 【Unity3D优化】平衡 Hide 与 Destroy:基于性能等级与 LRU 的 UI 管理策略与实践思考
  • PostgreSQL Certified Master 专访 | 第四期 贾桂军
  • 【Techlog】01入门-井筒数据整合软件的基本认识
  • 控制器调用服务层出现Cannot invoke ... 显示服务层bean对象为null
  • PostgreSQL 流程---更新
  • 编程语言学习
  • 环境搭建:centos7+docker+Oracle
  • 【datawhale组队学习】RAG技术 - TASK02
  • 3dmax 材质 / AO 通道渲染全流程
  • 3D检测笔记:相机模型与坐标变换
  • 超大型公共场所的智慧守护者——人脸动态识别与管理系统
  • 手机截图如何优雅地放在word里
  • 从原理到应用:GPS 定位技术的核心机制与未来发展
  • 心路历程-了解网络相关知识