动态规划:打家劫舍
打家劫舍Ⅰ
题目描述
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
示例 1:
输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。
示例 2:
输入:[2,7,9,3,1]
输出:12
解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
偷窃到的最高金额 = 2 + 9 + 1 = 12 。
代码
class Solution {
public int rob(int[] nums) {//动态规划
if(nums.length==0)
return 0;
if(nums.length==1)
return nums[0];
int[] dp=new int[nums.length];//dp[i]代表抢前i间房屋所能获得的最大收益,
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]);
//dp方程代表抢前i间房屋有两种选择,一种是抢前i-1间房屋,另一种是抢第i间和前i-2间
//取两种方法的最大值,这就把一个问题分成了小问题
}
return dp[nums.length-1];
}
}
打家劫舍Ⅱ
题目
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。
给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,能够偷窃到的最高金额。
示例 1:
输入:nums = [2,3,2]
输出:3
解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。
示例 2:
输入:nums = [1,2,3,1]
输出:4
解释:你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。
示例 3:
输入:nums = [0]
输出:0
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/house-robber-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
代码
/**
*把环形问题分解成两个线性问题,因为最后一间和第一间是相邻的,
*所以两者肯定不能同时偷,不偷第一间和不偷第二间哪种方法收益大返回那种
*/
class Solution {
public int rob(int[] nums) {
int length=nums.length;//房屋数量
if(length==0)
return 0;
if(length==1)
return nums[0];
if(length==2)
return Math.max(nums[0],nums[1]);
int[] dp1=new int[length];//dp1[]代表去掉第一间,偷取到nums[i]的收益最大值
int[] dp2=new int[length];//dp2[]代表去掉最后一间,偷取到nums[i]的收益最大值
dp1[0]=0;//不能偷nums[0]
dp1[1]=nums[1];
for(int i=2;i<length;++i){
dp1[i]=Math.max(//由之前得到的dp方程
dp1[i-1],
dp1[i-2]+nums[i]
);
}
dp2[0]=nums[0];
dp2[1]=Math.max(nums[0],nums[1]);
for(int i=2;i<length-1;++i){
dp2[i]=Math.max(
dp2[i-1],
dp2[i-2]+nums[i]
);
}
dp2[length-1]=dp2[length-2];//最后一间不能偷
return Math.max(dp1[length-1],dp2[length-1]);
}
}
打家劫舍Ⅲ
题目
- 涉及到二叉树,有时间重新学一遍