参考资料:
https://programmercarl.com/0198.%E6%89%93%E5%AE%B6%E5%8A%AB%E8%88%8D.html
题目描述:
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
示例 1:
输入:[1,2,3,1] 输出:4 解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。 偷窃到的最高金额 = 1 + 3 = 4 。
思路分析:
dp[i]:考虑0~i的房屋,获取的最大金币dp[i]
代码实现:
class Solution {
// public int rob(int[] nums){
// if(nums.length==1) return nums[0];
// int len=nums.length;
// int[] dp=new int[len];//dp[i]:包含i之前的房屋,能偷到的最大金额为dp[i]
// dp[0]=nums[0];
// dp[1]=Math.max(nums[0],nums[1]);
// for(int i=2;i<len;i++){
// dp[i]=Math.max(dp[i-2]+nums[i],dp[i-1]);
// }
// return dp[len-1];
// }
//空间优化
public int rob(int[] nums) {
int len=nums.length;
if(len==1) return nums[0];
int x=nums[0];
int y=Math.max(nums[0],nums[1]);
// if(len==2) return y;
int z=0;
for(int i=2;i<len;i++){
z=Math.max(x+nums[i],y);
x=y;
y=z;
}
return y;
}
}
题目描述:
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。
给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。
示例 1:
输入:nums = [2,3,2] 输出:3 解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的
思路分析:
与上题思路同,分别考虑1.含头不含尾 2.含尾不含头 的情况即可
代码实现:
class Solution {
public int rob(int[] nums) {
if(nums.length==1) return nums[0];
if(nums.length==2) return Math.max(nums[0],nums[1]);
int len=nums.length;
//考虑头,不考虑尾
int sum1=rob1(nums,0,len-1);
//考虑尾,不考虑头
int sum2=rob1(nums,1,len);
return Math.max(sum1,sum2);
}
public int rob1(int[] nums,int s,int e){
int x=0,y=0,z=0;
for(int i=s;i<e;i++){
z=Math.max(nums[i]+x,y);
x=y;
y=z;
}
return y;
}
}
题目描述:
小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为 root
。
除了 root
之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果 两个直接相连的房子在同一天晚上被打劫 ,房屋将自动报警。
给定二叉树的 root
。返回 在不触动警报的情况下 ,小偷能够盗取的最高金额 。
示例 1:
输入: root = [3,2,3,null,3,null,1] 输出: 7 解释: 小偷一晚能够盗取的最高金额 3 + 3 + 1 = 7
思路分析:
每个节点两个状态:dp[0],不偷当前节点获取的max;dp[1],偷当前节点获取的max
使用后序遍历,每个节点都会存储了之前的结果。
递推公式:res[0](不偷当前) = 左孩子(偷或不偷的max)+右孩子(偷或不偷的max)
res[1](偷当前) = cur.val(当前值)+left[0](不偷左孩子)+right[0](不偷右孩子)
代码实现:
/**
* 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) {
int[] res=robHelp(root);
return Math.max(res[0],res[1]);//0:不偷当前节点的最大值,1:偷当前节点的最大值
}
int[] robHelp(TreeNode cur){
if(cur==null) return new int[2];
int[] res=new int[2];
int[] left=robHelp(cur.left);
int[] right=robHelp(cur.right);
res[0]=Math.max(left[0],left[1])+Math.max(right[0],right[1]);
res[1]=cur.val+left[0]+right[0];
return res;
}
}