198. 打家劫舍
var rob = function(nums) {
// 1、dp[i]表示偷前i家的最高金额
const n = nums.length
const dp = new Array(n+1)
// 2、初始化dp,dp[0] dp[1]
dp[0] = 0 // 表示偷0家,即没有偷
dp[1] = nums[0] // 表示偷第一家
// 3、遍历更新dp数组
for(let i=2; i<=n; i++){
// 由于不能偷相邻的,所以偷不偷第i家取决于是偷i-1家,还是偷i-2家。
// 偷i-1家就不能偷i家,偷i-2家就可以偷i家,取其中产生最大的那个即可
dp[i] = Math.max(dp[i-1],dp[i-2]+nums[i-1])
}
return dp[n]
};
213. 打家劫舍 II
题目
对于环形就是相当于第一个和最后一个房屋不可以同时偷,那么分两种情况,注意需要转换到偷的上面。不偷第一个,相当于偷第2个到偷第n个。不偷第n个,相当于偷第1个到偷第n-1个。取这两种情况的最大。
var rob = function(nums) {
// 定义两个dp数组,对应两种情况
const n = nums.length
const dp1 = new Array(n+1)
const dp2 = new Array(n+1)
// 只有一家的时候,就是这家
if(n==1) return nums[0]
// 总的标准就是第一家和最后一家不可以同时偷
// 对于dp1,偷1~n-1家
dp1[0] = 0
dp1[1] = nums[0]
for(let i=2; i<=n-1; i++){
dp1[i] = Math.max(dp1[i-1],dp1[i-2]+nums[i-1])
}
// 对于dp2,偷2~n家
dp2[1] = 0
dp2[2] = nums[1]
for(let i=3; i<=n; i++){
dp2[i] = Math.max(dp2[i-1],dp2[i-2]+nums[i-1])
}
// 拿到这两种情况的最大值
return Math.max(dp1[n-1],dp2[n])
};
337. 打家劫舍 III
var rob = function(root) {
// 递归遍历二叉树,每次返回的是一个节点偷或者不偷所得的金钱,两种情况。
// 即是一个dp数组,长度为2。dp[0]表示不偷节点所得,dp[1]表示偷节点所得。
var dfs = function(root){
// 结束条件,节点为空,那么就都是0
if(!root) return [0,0]
// 后序遍历,先得到左右节点偷或者不偷所得,dfs返回的就是这个dp
let left = dfs(root.left)
let right = dfs(root.right)
// 根节点的情况,偷或者不偷所得
const Do = Math.max(left[0],left[1]) + Math.max(right[0],right[1])// 拿到左右的最大情况
const DoNot = root.val + left[0] + right[0] // 不可以偷左右
// 返回数组,两种情况
return [Do,DoNot]
}
// 最后返回的是根节点偷或者不偷的状态
let res = dfs(root)
return Math.max(res[0],res[1])
};