算法-动态规划-打家劫舍2
算法-动态规划-打家劫舍2
1 题目概述
1.1 题目出处
https://leetcode-cn.com/problems/house-robber-ii/
1.2 题目描述
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。
示例 1:
输入: [2,3,2]
输出: 3
解释: 你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。
示例 2:
输入: [1,2,3,1]
输出: 4
解释: 你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。
2 动态规划
2.1 思路
思考,每一个房屋是否行窃如何决定?
第i个房屋最大价值 = Math.max(选当前+前i-2个房屋的价值和, 不选当前,前i-1个房屋的价值和)
那么这就是典型的动态规划问题。
但是这和打家劫舍1.0不同的是,这里首尾房屋成环,也不能同时选,所以需要分别考虑选择第一个或选择最后一个房屋的情况,取计算结果的大者为最终结果。
2.2 代码
class Solution {
public int rob(int[] nums) {
int result = 0;
// 选择某一个的条件是
// 价值大于相邻的前一个
if(nums == null || nums.length == 0){
return result;
}
if(nums.length == 1){
return nums[0];
}
// 分为两种情况考虑:选择第一个、不选第一个
// 选择第一个,则不选第二个后最后一个
int tmp1 = nums[0];
if(nums.length == 4){
tmp1 += nums[2];
} else if(nums.length > 4){
int dp[] = new int[nums.length];
// 第i个房屋最大价值 = Math.max(选当前+前i-2个房屋的价值和,不选当前,前i-1个房屋的价值和)
dp[2] = nums[2];
dp[3] = Math.max(nums[2], nums[3]);
for(int i = 4; i < nums.length - 1; i++){
dp[i] = Math.max(nums[i] + dp[i-2], dp[i-1]);
}
tmp1 += dp[nums.length - 2];
}
// 不选第一个,则可选第二个后最后一个
int tmp2 = 0;
if(nums.length == 2){
tmp2 = nums[1];
}else{
int dp[] = new int[nums.length];
// 第i个房屋最大价值 = Math.max(选当前+前i-2个房屋的价值和,不选当前,前i-1个房屋的价值和)
dp[1] = nums[1];
dp[2] = Math.max(nums[1], nums[2]);
for(int i = 3; i < nums.length; i++){
dp[i] = Math.max(nums[i] + dp[i-2], dp[i-1]);
}
tmp2 += dp[nums.length - 1];
}
return Math.max(tmp1, tmp2);
}
}
冗余更少的代码:
class Solution {
public int rob(int[] nums) {
int result = 0;
// 选择某一个的条件是
// 价值大于相邻的前一个
if(nums == null || nums.length == 0){
return result;
}
if(nums.length == 1){
return nums[0];
}
// 分为两种情况考虑:选择第一个、不选第一个
// 选择第一个,则不选第二个后最后一个
int tmp1 = nums[0];
tmp1 += rob(nums, 2, nums.length - 2);
// 不选第一个,则可选第二个后最后一个
int tmp2 = rob(nums, 1, nums.length - 1);
return Math.max(tmp1, tmp2);
}
public int rob(int[] nums, int start, int end){
if(start > nums.length || end < start){
return 0;
}else if (start == end){
return nums[start];
}
int[] dp = new int[nums.length];
dp[start] = nums[start];
dp[start+1] = Math.max(nums[start], nums[start+1]);
for(int i = start + 2; i <= end; i++){
dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
}
return dp[end];
}
}
2.3 时间复杂度
O(N)
2.4 空间复杂度
O(N)
还没有评论,来说两句吧...