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

代码随想录打卡Day39

今天是打家劫舍专题,三道题全都看了讲解,第一次做感觉确实是无从下手。。。不过了解了原理之后代码很快就写出来了。

198.打家劫舍

这道题使用一维dp数组,首先确定dp数组的含义,dp[i]为考虑偷下标[0, i]家的情况下所能获得的最大收益,对于每一家,都有两个状态,偷与不偷,当选择偷时,则收益为当前房子的金币 + 上上个房子的最大收益(上上个房子不一定非要偷),当选择不偷时,其收益为上个房子的最大收益(可偷可不偷)。

class Solution {
public:
    int rob(vector<int>& nums) {
        //1.确定dp[i]的含义:考虑下标在[0, i]的房间的情况下,所能偷的最多的钱为dp[i]
        //2.确定递推公式  dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
        //3.dp数组初始化 dp[0] = nums[0], dp[1] = max(nums[0], nums[1]);
        //4.确定遍历顺序:从小到大遍历
        //5.打印数组(省略)
        vector<int> dp(nums.size());
        //初始化
        dp[0] = nums[0];
        if(nums.size() > 1)
            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.back();
    }
};

213.打家劫舍II

这个环形问题我一开始想的是用求余操作来解决,但是想了半天也没想出来用求余怎么做,于是还是去看视频了。。这个环形问题主要还是拆解成两个线性问题,首元素和尾元素不能同时纳入考虑范围,所以构造两个数组,一个是不包含尾元素的向量,另一个是不包含首元素的向量,这就转换成了上一道题的思路,分别对两个线性表求最大收益,取其中的较大值返回即可。

class Solution {
public:
    int rob(vector<int>& nums) {
        //1.确定dp[i]的含义:考虑下标在[0, i]的房间的情况下,所能偷的最多的钱为dp[i]
        //2.确定递推公式  dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
        //3.dp数组初始化 dp[0] = nums[0], dp[1] = max(nums[0], nums[1]);
        //4.确定遍历顺序:从小到大遍历
        //5.打印数组(省略)
        if(nums.size() == 1) return nums[0];
        //考虑首元素而不考虑尾元素的情况
        vector<int> nums1(nums.begin(), nums.end() - 1); //[0, nums.size() - 2]
        //考虑尾元素而不考虑首元素的情况
        vector<int> nums2(nums.begin() + 1, nums.end()); //[1, nums.size() - 1]
        vector<int> dp1(nums1.size());
        vector<int> dp2(nums2.size());
        dp1[0] = nums1[0];
        dp2[0] = nums2[0];
        if(dp1.size() > 1){
            dp1[1] = max(nums1[0], nums1[1]);
            dp2[1] = max(nums2[0], nums2[1]);
        }
        for(int i = 2; i < nums1.size(); i++){
            dp1[i] = max(dp1[i - 2] + nums1[i], dp1[i - 1]);
            dp2[i] = max(dp2[i - 2] + nums2[i], dp2[i - 1]);
        }  
        return max(dp1.back(), dp2.back());
    }
};

337.打家劫舍III

这道题是树形dp,以前从来没见过,感觉对我来说确实还是太难了。这道题需要用一个大小为2的一维数组保存每一个节点偷与不偷时的最大收益,通过递归遍历二叉树的所有节点,得到每个节点偷与不偷时的最大收益,这里直接定义一个返回向量的递归遍历函数,当选择偷根节点时,左右孩子都不能偷,则收益为root -> val + left_dp[1] + right_dp[1],选择不偷根节点时,则返回左右孩子各自的最大收益的总和(并不是根节点没偷就一定要偷其左右孩子),则收益为max(left_dp[0], left_dp[1]) + max(right_dp[0], right_dp[1])。在主函数中直接拿一个向量接住调用遍历函数且输入参数为根节点root时的结果,再返回向量中的较大值即可。

class Solution {
public:
    vector<int> Travelsal(TreeNode* root){
        //确定终止条件
        if(root == NULL) return {0, 0};
        //后序遍历,dp[0]为偷时的最大金币,dp[1]为不偷时的最大金币
        vector<int> left_dp = Travelsal(root -> left);  //左孩子节点偷与不偷
        vector<int> right_dp = Travelsal(root -> right); //右孩子节点偷与不偷
        vector<int> root_dp;
        //根节点选择偷,左孩子和右孩子都不能偷
        root_dp.push_back(left_dp[1] + right_dp[1] + root -> val);
        //根节点选择不偷,则左孩子和右孩子可偷可不偷,取决于哪种状态的收益更大
        root_dp.push_back(max(left_dp[0], left_dp[1]) + max(right_dp[0], right_dp[1]));
        return root_dp;
    }
    int rob(TreeNode* root) {
        vector<int> dp = Travelsal(root);
        return max(dp[0], dp[1]);
    }
};

明天就可以休息了,nice!!


http://www.kler.cn/a/321463.html

相关文章:

  • 【Java基础-26.1】Java中的方法重载与方法重写:区别与使用场景
  • vue-axios+springboot实现文件流下载
  • VSCode 性能优化指南:提高编码效率,减少资源占用
  • Linux搭建TRELLIS详细流程
  • JavaScript中的Set、Map、WeakSet和WeakMap
  • windows11家庭版安装docker无法识别基于wsl2的Ubuntu
  • 【devops】devops-ansible模块介绍
  • 卷积神经网络-迁移学习
  • Spire.PDF for .NET【页面设置】演示:对PDF 文件进行分页
  • 【ASE】第一课_双面着色器
  • 增量式编码器实现原理
  • 使用python爬取豆瓣网站?如何简单的爬取豆瓣网站?
  • FPGA中系统门数和逻辑门数的理解
  • 智视臂传-AI视觉触感未来丨OPENAIGC开发者大赛高校组AI创作力奖
  • 计算机毕业设计 基于Hadoop的智慧校园数据共享平台的设计与实现 Python 数据分析 可视化大屏 附源码 文档
  • 性能设计模式
  • 1.6 判定表
  • 【C++与数据结构】搜索二叉树(BinarySearchTree)
  • 数据仓库-数据质量规范
  • 问:聊聊JAVA中的共享锁和独占锁?
  • 了解针对基座大语言模型(类似 ChatGPT 的架构,Decoder-only)的重头预训练和微调训练
  • 前端Vue 基础学习1
  • 暗黑破坏神4新资料片憎恶之躯即将上线,第六赛季暗黑破坏神4搬砖如何获得最大收益?
  • 响应式的几种解决方案——媒体查询、flex、grid、多列布局、瀑布流和数据可视化屏幕的缩放处理
  • 极狐GitLab 17.4 重点功能解读【三】
  • crontab -e 修改为vim 编辑