题目传送门:LeetCode 198. 打家劫舍
题目详情:
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
示例 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 。提示:
1 <= nums.length <= 100
0 <= nums[i] <= 400
我很奇怪他这警报装置是不是有问题,为什么偷我家不会报警,邻居家被偷了却会报警。
专业的小偷就要用专业的方法,像这道题就果断应用动态规划来计算一夜之内能够偷窃到的最高金额。
我们首先设置一个dp数组,这个数组和问题给出的数组等长,下标 i 即为当前小偷所在的房子(即偷到哪一间房子里了),而 dp[i] 为当前所偷窃到的最高金额。
接下来思考状态转移方程:当只有一间房屋时,我们能且只能偷这间房,使所能偷到的金额最高;而当有两间房屋时,我们因为防盗系统的限制,我们要在这两间屋子中选择金额较高的房屋进行盗窃,当房屋数 i 大于 2 时,我们就有了两种选择:1.偷第 i 间屋子,我们现在的总金额为该房屋所能偷到的金额数 + 前 i-2 的房屋所能偷到的最大金额数;2.不偷第 i 间屋子,我们现在的总金额为前 i-1 的房屋所能偷到的最大金额数;
所以状态方程为:dp[ i ] = max(dp[ i-2 ]+当前房屋所能偷到的金额数,dp[ i-1 ]) ( i>2 )
dp[ 0 ] = 第一间房屋所能偷到的金额数;
dp[ 1 ] = 前两间房屋中所能偷到的最大金额数;
代码如下(c++):
class Solution {
public:
int rob(vector<int>& nums) {
int length=nums.size();
if(length==1)
{
return nums[0];
}
vector<int>dp(length,0);
dp[0]=nums[0];//只有一间房屋
dp[1]=max(nums[0],nums[1]);//有两间房屋
for(int i=2;i<length;i++)//房屋数大于2时从第三间屋子开始选择偷或者不偷
{
dp[i]=max(dp[i-2]+nums[i],dp[i-1]);
}
return dp[length-1];
}
};
比较基础的动态规划的题目,下面来个稍微变化一点的题目
题目传送门:LeetCode 213. 打家劫舍II
题目详情:
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。
给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。
示例 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 = [1,2,3]
输出:3提示:
1 <= nums.length <= 100
0 <= nums[i] <= 1000
房屋围成一圈,可以同步为我们偷盗的范围有2中选择:1.从第 1 间房屋开始到 倒数第二间 房屋【0,n-1】结束,在每一间房屋选择偷或者不偷;2.从第 2 间房屋开始到 最后一间房屋 【1,n】结束,在每一间房屋选择偷或者不偷;最后再在这两种选择中挑选所能偷到的最大金额的那一种。这时我们发现除了范围不一样后,其他内容和 打家劫舍I 相同,于是将 I 中的代码稍作修改后就得到了 II 的代码:
代码如下(c++):
class Solution {
public:
int rob(vector<int>& nums) {
int length=nums.size();
if(length==1)
{
return nums[0];
}
if(length==2)
{
return max(nums[0],nums[1]);
}
vector<int>dp(length,0);
dp[1]=nums[1];//第二种选择,偷盗范围为【1,n】
dp[2]=max(nums[1],nums[2]);
for(int i=3;i<length;i++)//在每间房屋考虑偷还是不偷
{
dp[i]=max(dp[i-2]+nums[i],dp[i-1]);
}
dp[0]=nums[0];//第一种选择,偷盗范围为【0,n-1】
dp[1]=max(nums[0],nums[1]);
for(int i=2;i<length-1;i++)
{
dp[i]=max(dp[i-2]+nums[i],dp[i-1]);
}
return max(dp[length-1],dp[length-2]);//在两种选择种挑选最大的那一种
}
};
计算机204 zjr