Day40 力扣动态规划 :198.打家劫舍 |213.打家劫舍II | 337.打家劫舍III
最佳答案 问答题库828位专家为你答疑解惑
Day40 力扣动态规划 :198.打家劫舍 |213.打家劫舍II | 337.打家劫舍III
- 198.打家劫舍
- 第一印象
- 看完题解的思路
- 实现中的困难
- 感悟
- 代码
- 213.打家劫舍II
- 第一印象
- 看完题解的思路
- 实现中的困难
- 感悟
- 代码
- 337.打家劫舍III
- 第一印象
- 看完题解的思路
- 实现中的困难
- 感悟
- 代码
今天就是打家劫舍的一天,这个系列不算难,大家可以一口气拿下。
198.打家劫舍
视频讲解:https://www.bilibili.com/video/BV1Te411N7SX
https://programmercarl.com/0198.%E6%89%93%E5%AE%B6%E5%8A%AB%E8%88%8D.html
第一印象
直接看题解学习新算法
看完题解的思路
这道题其实不难,和爬楼梯很像,就是dp算法基本的做法:先写几个,找找规律,就做出来了
最主要的是dp数组的含义:考虑到下标为 i 的那户,能偷的最大金额是 dp[i] 元 (考虑到第3家,不代表一定偷第三家,比如最后返回的事dp[length - 1],不代表一定偷了最后一家)
实现中的困难
注意nums如果只有一个元素的话,初始化就回数组越界了。
感悟
动笔算,不要懒
代码
class Solution {public int rob(int[] nums) {if (nums.length == 1) return nums[0];int[] dp = new int[nums.length];dp[0] = nums[0];dp[1] = Math.max(nums[0], nums[1]);for (int i = 2; i < dp.length; i++) {dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]);}return dp[dp.length - 1];}
}
213.打家劫舍II
视频讲解:https://www.bilibili.com/video/BV1oM411B7xq
https://programmercarl.com/0213.%E6%89%93%E5%AE%B6%E5%8A%AB%E8%88%8DII.html
第一印象
对比起抢劫1,就是成环了。那么偷了第一家就不能偷最后一家,感觉影响初始化的。
那么我觉得就是分两种,一个是抢了第一家,就不能抢最后一家。另一个是 抢了第二家,最后一家抢不抢看情况。最后两个数组取最大的。
虽然方法比较笨,但是做对了,看看题解有没有精妙的。
看完题解的思路
和我一样,我是天才
实现中的困难
无
感悟
真是天才
代码
我的笨方法。
class Solution {public int rob(int[] nums) {if (nums.length == 1) return nums[0];int[] dpOne = new int[nums.length];int[] dpLast = new int[nums.length];//抢第一家,不抢第二家,且不抢最后一家dpOne[0] = nums[0];dpOne[1] = dpOne[0];//不抢第一家,抢第二家,最后一家递推dpLast[0] = 0;dpLast[1] = nums[1];for (int i = 2; i < dpOne.length - 1; i++) {dpOne[i] = Math.max(dpOne[i - 2] + nums[i], dpOne[i - 1]);}dpOne[dpOne.length - 1] = dpOne[dpOne.length - 2];for (int i = 2; i < dpLast.length; i++) {dpLast[i] = Math.max(dpLast[i - 2] + nums[i], dpLast[i - 1]);}return dpOne[dpOne.length - 1] > dpLast[dpLast.length - 1] ? dpOne[dpOne.length - 1] : dpLast[dpLast.length - 1];}
}
337.打家劫舍III
视频讲解:https://www.bilibili.com/video/BV1H24y1Q7sY
https://programmercarl.com/0337.%E6%89%93%E5%AE%B6%E5%8A%AB%E8%88%8DIII.html
第一印象
就是不能同时打劫父子节点,但也不是一层一层来。要看最大的
我试试
失败了,树形的我找不到dp数组和递推公式
看完题解的思路
悟了,这道题挺复杂的,又要dp又要递归,但我觉得核心其实是递归。
递归的思路就是对于一个节点来说,它有两个可能,偷或者不偷。
- 偷的话,它的价值就是自己 + 左孩子不偷的价值 + 右孩子不偷的价值
- 不偷的话,它的价值就是左孩子偷或者不偷更大的那个价值 + 右孩子偷或者不偷更大的价值
看到这,也该知道是后序遍历才对,因为要根据左右孩子的价值来算自己的。
递归的问题基本就解决了。
那么dp数组在哪呢?如果保存左孩子不偷的价值和偷的价值,就是dp数组。这个数组大小是2,dp[0] 代表不偷这个节点的最大价值,dp[1]代表偷这个节点的最大价值。
那么dp数组怎么记录每个节点的呢?把它当做递归的返回值,他在一层层递归的时候,返回给父节点用于计算。
所以递归三部曲
- 返回值和返回值:返回值是dp数组,参数是节点
- 终止条件:节点为null,就返回 「0, 0」这样的数组
- 单层递归逻辑:就是上面说的递归思路。
我自己写写试试
做对了
实现中的困难
理解思路之后就没有实现困难了
感悟
关键是要讨论当前节点抢还是不抢,也就是所谓的状态。dp题目感觉首先要抓住状态,然后看这个状态怎么变化的,找到那个状态转移公式,也就是递推公式。
这道题目算是树形dp的入门题目
代码
class Solution {public int rob(TreeNode root) {int[] dp = robTree(root);return Math.max(dp[0], dp[1]);}private int[] robTree(TreeNode node) {if (node == null) {int[] array = {0, 0};return array;}//单层递归逻辑int[] leftdp = robTree(node.left);int[] rightdp = robTree(node.right);//根据左右节点算出自己int curSteal = leftdp[0] + rightdp[0] + node.val;int curNotSteal = Math.max(leftdp[0], leftdp[1]) + Math.max(rightdp[0], rightdp[1]);//不偷自己dp[0]偷自己dp[1]int[] dp = {curNotSteal, curSteal};return dp;}
}
99%的人还看了
相似问题
猜你感兴趣
版权申明
本文"Day40 力扣动态规划 :198.打家劫舍 |213.打家劫舍II | 337.打家劫舍III":http://eshow365.cn/6-26939-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!