Day 42 算法记录|动态规划 09 (打家劫舍)

这篇具有很好参考价值的文章主要介绍了Day 42 算法记录|动态规划 09 (打家劫舍)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

198.打家劫舍

1.dp[i]:考虑下标i(包括i)以内的房屋,最多可以偷窃的金额为dp[i]。
2.dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
3.初始化,dp[0] 和 dp[1],dp[0] 一定是 nums[0],dp[1] = max(nums[0], nums[1]);
3.遍历顺序,dp[i] 是根据dp[i - 2] 和 dp[i - 1] 推导出来的,那么一定是从前到后遍历!

class Solution {
    public int rob(int[] nums) {
        if(nums ==null||nums.length ==0) return 0;
        if(nums.length ==1) return nums[0];

        int len = nums.length;
        int[] dp = new int[len];
        dp[0]=nums[0];
        dp[1] = Math.max(nums[0],nums[1]);

        for(int i =2;i<nums.length;i++){
            dp[i] = Math.max(dp[i-1],dp[i-2]+nums[i]);
        }

return dp[len-1];
    }
}

进一步对滚动数组的空间优化 dp数组只存与计算相关的两次数据
因为当前能偷的最多与上一家还有上上一家有关

class Solution {
    public int rob(int[] nums) {
   
        if(nums.length ==1) return nums[0];

        int len = nums.length;
        int[] dp = new int[2];
        dp[0]=nums[0]; //上上家
        dp[1] = Math.max(nums[0],nums[1]); // 上一家
        int res =0;

        for(int i =2;i<nums.length;i++){
            res = Math.max(dp[1],dp[0]+nums[i]); //当前家的最大值
            dp[0] = dp[1];
            dp[1] = res;

        }

    return dp[1];
    }
}

213.打家劫舍II

这个视频讲解的不错
这道题与上一道不同的是首尾相连
那么第一个和最后一个一定只能选择其中一个
Day 42 算法记录|动态规划 09 (打家劫舍),算法,动态规划,数据结构

class Solution {
    public int rob(int[] nums) {
      if(nums.length == 1) return nums[0];
      int n = nums.length;
    int res = Math.max(robAction(Arrays.copyOfRange(nums,0,n-1)),robAction(Arrays.copyOfRange(nums,1,n)));
    return res;

    }

    public int robAction(int [] nums){
        if(nums.length ==1) return nums[0];

        int[] dp = new int[2];
        dp[0] = nums[0];
        dp[1] = Math.max(nums[0],nums[1]);
        int temp =0;
        for(int i=2;i<nums.length;i++){
            temp = Math.max(dp[1],dp[0]+nums[i]);
            dp[0] = dp[1];
            dp[1] = temp;
        }
        return dp[1];
    }
}

337.打家劫舍 III

每个节点是否被选中,取决于该节点的左右子节点是否被选
方法一递归
从根节点开始遍历,分为两种情况,偷当前节点和孙子节点,不偷当前节点,偷孩子
再对每个结点比较大小

class Solution {
    // 1.递归去偷,超时
    public int rob(TreeNode root) {
        if (root == null)
            return 0;
        int money = root.val;
        if (root.left != null) {
            money += rob(root.left.left) + rob(root.left.right);
        }
        if (root.right != null) {
            money += rob(root.right.left) + rob(root.right.right);
        }
        return Math.max(money, rob(root.left) + rob(root.right));
    }
    }

上面的递归超时,因为出现了很多重复的步骤,改进记忆法递归
方法二递归去偷,记录状态
从根节点开始遍历的时候,就用一个类似数组的集合进行存放,减少遍历次数

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public int rob(TreeNode root) {
    Map<TreeNode,Integer> memo = new HashMap<>();
    return robAction(root,memo);
    }

    public int robAction(TreeNode root, Map<TreeNode,Integer> memo ){
       //停止条件
       if(root == null) return 0;

       // 避免重复操作
        if(memo.containsKey(root)){
            return memo.get(root);
        }

      
        //1.选择当前节点 再偷孙子
          int cur = root.val;
        if(root.left !=null){
            cur +=robAction(root.left.left,memo)+robAction(root.left.right,memo);
        }

        if(root.right != null){
            cur +=robAction(root.right.left,memo) + robAction(root.right.right,memo);
        }
        //2.不偷当前节点,去偷孩子
        int  cur1 = robAction(root.left,memo)+robAction(root.right,memo);
        //比较上面两种选择
        int res = Math.max(cur,cur1);
        memo.put(root,res);
        return res;
    }
}

方法三: 状态标记递归
每个节点是否选择,取决于其左右子节点(所以只需要记录临近节点的状态,其余就不用管,就像上一道里面的上一个,上上个)

dp[0],dp[1]分别表示当前节点没有被选中,和被选中
left[0],left[1]表示其左孩子没选中和选中,right同样

对于当前节点:
不偷:Max(左孩子不偷,左孩子偷) + Max(又孩子不偷,右孩子偷),我不偷,我的孩子可偷可不偷
root[0] = Math.max(rob(root.left)[0], rob(root.left)[1]) +Math.max(rob(root.right)[0], rob(root.right)[1])
偷:左孩子不偷+ 右孩子不偷 + 当前节点偷,我偷,孩子必然不能偷文章来源地址https://www.toymoban.com/news/detail-607706.html

class Solution {
    public int rob(TreeNode root) {
     int[] dp = robAction(root);
     return Math.max(dp[0],dp[1]);
    }

    public int[] robAction(TreeNode root ){
       //停止条件
       if(root == null) return new int[2];

        
       int[] left = robAction(root.left);
       int[] right = robAction(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;
    }
}

到了这里,关于Day 42 算法记录|动态规划 09 (打家劫舍)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【算法|动态规划No.10】leetcode LCR 089. 打家劫舍 & LCR 090. 打家劫舍 II

    个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 🍔本专栏旨在提高自己算法能力的同时,记录一下自己的学习过程,希望对大家有所帮助 🍓希望我们一起努力、成长,共同进步。

    2024年01月20日
    浏览(32)
  • 动态规划_打家劫舍(Ⅰ~Ⅲ)

    打家劫舍系列 返回最大金额 不能同时取相邻两个数 数组数据全部非负 ①dp数组含义 dp[i]表示前i个数中按规则取出的最大总和 ②递推公式 dp[i]=max(dp[i-1],dp[i-2]+nums[i]) 当前最优可以从两个状态推出(前提是前面已经为最优解): 1° 前一个数未取:则当前数取了,则总和最大

    2024年02月03日
    浏览(26)
  • 【学会动态规划】打家劫舍 II(12)

    目录 动态规划怎么学? 1. 题目解析 2. 算法原理 1. 状态表示 2. 状态转移方程 3. 初始化 4. 填表顺序 5. 返回值 3. 代码编写 写在最后: 学习一个算法没有捷径,更何况是学习动态规划, 跟我一起刷动态规划算法题,一起学会动态规划! 题目链接:213. 打家劫舍 II - 力扣(Lee

    2024年02月15日
    浏览(28)
  • 力扣198. 打家劫舍(java 动态规划)

    Problem: 198. 打家劫舍 1.构建多阶段决策模型:n个房屋对应n个阶段,每一个阶段决定一个房间是偷还是不偷,两种决策:偷、不偷 2.定义状态:不能记录每个阶段决策完之后,小偷可偷的最大金额,需要记录不同决策对应的最大金额,也就是:这个房屋偷-对应的最大金额;这

    2024年01月21日
    浏览(40)
  • leetcode-打家劫舍专题系列(动态规划)

    你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动

    2024年04月14日
    浏览(31)
  • 动态规划-经典dp(打家劫舍,股票等)

    1.1.1 爬楼梯  由于求的是组合数,我们将不同路径相加即可 dp定义: dp[i]为爬到第i阶楼梯的方法数; 转移方程: 初始化:  由于涉及到i-2和i-1,那么我们要从i=2开始遍历,因此要初始化dp[0] = 0,dp[1] = 1(根据定义) 遍历顺序: 从左往右  完整代码:  1.1.2 使用最小花费爬楼梯

    2024年01月19日
    浏览(28)
  • 【LeetCode热题100】198. 打家劫舍(动态规划)

    你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统, 如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动

    2024年04月11日
    浏览(29)
  • leetcode 343.整数拆分 198.打家劫舍(动态规划)

       OJ链接 :leetcode 343.整数拆分 代码:  OJ链接 :198.打家劫舍    代码:

    2024年02月05日
    浏览(37)
  • Java 动态规划 Leetcode 213. 打家劫舍 II

    代码展示:         该题其实是Java 动态规划 面试题 17.16. 按摩师的变种,增加了一个首尾是相邻的条件,而我们解决该题也要用到链接的这道题的思想,可以先去看一下上面这篇博客 此题可以采用动态规划的方法进行解决,根据解决动态规划题目的5大步骤进行逐步分析

    2024年02月13日
    浏览(26)
  • C++动态规划经典试题解析之打家劫舍系列

    力扣上有几道与打家劫舍相关的题目,算是学习动态规划时常被提及的经典试题,很有代表性,常在因内大大小小的社区内看到众人对此类问题的讨论。 学习最好的方式便是归纳总结、借鉴消化,基于这个目的,本文对此类问题也做了讲解,在一些优秀思想的基础上添加了个

    2024年02月13日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包