一、打家劫舍
198:你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
class Solution {
public int rob(int[] nums) {
int length =nums.length;
if(length==1) return nums[0];
int[] dp =new int[length];
dp[0]=nums[0];
dp[1]=Math.max(nums[0],nums[1]);
for(int i = 2;i<length;i++){
//d[i]表示 下标i以及之前的房屋 能拿到的多金额
//d[i]来源有两种可能: 1.不拿nums[i] 2. 拿第nums[i]
dp[i]=Math.max(dp[i-1],dp[i-2]+nums[i]);
}
return dp[length-1];
}
}
二、打家劫舍
213:你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。
class Solution {
public int rob(int[] nums) {
int length = nums.length;
if(length==1)return nums[0];
if(length==2)return Math.max(nums[0],nums[1]);
int[] dp_head = new int[length-1];
int[] dp_tail = new int[length-1];
dp_head[0]=nums[0];
dp_head[1]=Math.max(nums[0],nums[1]);
dp_tail[0]=nums[1];
dp_tail[1]=Math.max(nums[1],nums[2]);
//考虑两种情况:第一种去掉最后一个元素考虑最大值,第二种去掉第一个元素考虑最大值,最终结果肯定在这两种情况之内
for(int i = 2;i<length-1;i++)
dp_head[i]=Math.max(dp_head[i-1],dp_head[i-2]+nums[i]);
for(int i = 2;i<length-1;i++)
dp_tail[i]=Math.max(dp_tail[i-1],dp_tail[i-2]+nums[i+1]);
return Math.max(dp_head[length-2],dp_tail[length-2]);
}
}
三、打家劫舍III
337:在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。
class Solution {
public int rob(TreeNode root) {
int[] result = travel(root);
return Math.max(result[0],result[1]);
}
//int[],存两个数,第一个代表不偷该节点的最大值,第二个代表偷该节点的最大值
public int[] travel(TreeNode root){
if(root==null){
return new int[]{0,0};
}
if(root.left==null&&root.right==null){
return new int[]{0,root.val};
}
int[] left = travel(root.left);
int[] right = travel(root.right);
int nosteal = Math.max(left[0],left[1])+Math.max(right[0],right[1]);
int issteal = left[0]+right[0]+root.val;
return new int[]{nosteal,issteal};
}
}