说明
打家劫舍问题算是动态规划问题中的一个小分支,这里单独写一篇文章介绍,需要注意的是,本片文章没有很详细的讲解,仅仅做一个汇总作用。至于动态规划问题除了处理的详细步骤我在我的另一篇文章中详细介绍过。具体解决步骤请移步观看——动态规划基础篇。
例题讲解
1.打家劫舍
1.1题目详情
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
提示:
- 1 <= nums.length <= 100
- 0 <= nums[i] <= 400
1.2一维dp
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[] dp=new int[nums.length];
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-2]+nums[i],dp[i-1]);
}
return dp[nums.length-1];
}
}
1.3空间优化
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 a=nums[0];
int b=Math.max(nums[0],nums[1]);
int c=0;
for(int i=2;i<nums.length;i++){
c=Math.max(a+nums[i],b);
a=b;
b=c;
}
return c;
}
}
2.打家劫舍||
2.1题目详情
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。
给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。
提示:
- 1 <= nums.length <= 100
- 0 <= nums[i] <= 1000
2.2
public class Solution {
public int rob (int[] nums) {
// write code here
if(nums.length==1) return nums[0];
if(nums.length==2) return Math.max(nums[0],nums[1]);
int val1=robTree(nums,0,nums.length-2);
int val2=robTree(nums,1,nums.length-1);
return Math.max(val1,val2);
}
public int robTree(int[] nums,int start,int end){
if(end-start==1) return Math.max(nums[start],nums[end]);
int a=nums[start];
int b=Math.max(nums[start],nums[start+1]);
int c=0;
for(int i=start+2;i<=end;i++){
c=Math.max(a+nums[i],b);
a=b;
b=c;
}
return c;
}
}
3.打家劫舍|||
3.1题目详情
小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为 root 。
除了 root 之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果 两个直接相连的房子在同一天晚上被打劫 ,房屋将自动报警。
给定二叉树的 root 。返回 在不触动警报的情况下 ,小偷能够盗取的最高金额 。
提示:
- 树的节点数在 [1, 104] 范围内
- 0 <= Node.val <= 104
3.2 动态规划+递归
class Solution {
/**
robTree(TreeNode cur):返回一个长度为2的一维数组res,
res[0]:不偷该节点所得的最大金钱
res[1]:偷该节点所得的最大金钱
*/
public int rob(TreeNode root) {
int[] res=robTree(root);
return Math.max(res[0],res[1]);
}
public int[] robTree(TreeNode cur){
//当前节点为空:返回值都为0的数组
if(cur==null) return new int[2];
int[] left=robTree(cur.left);
int[] right=robTree(cur.right);
//val1:表示偷当前节点,那么根据题意可知,其左右子节点都不能偷
int val1=cur.val+left[0]+right[0];
//val2:表示不偷当前节点,那么根据题意可知,其左右子节点都可以偷,但不一点必须要偷
int val2=Math.max(left[0],left[1])+Math.max(right[0],right[1]);
int[] res=new int[2];
res[0]=val2;
res[1]=val1;
return res;
}
}