发表此贴以纪念我做出的第一道leetcode中级题
在学习了动态规划专题,耗尽脑汁研究了两三道动态规划简单题之后,没想到自己竟然能很轻松地敲出了一道中级题!(当然也可能是这个题的难度在中级题里面算简单题QWQ)
题目描述:
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
示例 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]为以i为最后一个房屋的前i号房屋能偷取的最多金额
分析:
若要偷窃第i个房屋,则偷不了第i-1个房屋,那么偷取的总金额等于该房屋(i)的金额(nums[i])加上i-2号及之前的房屋能偷取的金额的最大值(dp[i-2])。(nums[i]+dp[i-2])
若不偷取第i给房屋,则能偷取第i-1号的房屋,偷取的总金额等于i-1号及之前的房屋能偷取的金额的最大值(dp[i-1])。
两者比较,取最大值,则为前i号房屋能偷取的最多金额(dp[i])
可得状态转移方程:
dp[i]=max(dp[i-1],dp[i-2]+nums[i])
遍历完整个数组后,最后dp[i]的值即为最大金额。
代码:
class Solution {
public:
int rob(vector<int>& nums) {
if(nums.size()==1)
return nums[0];
int*dp=new int[nums.size()];
dp[0]=nums[0];
dp[1]=nums[1]>dp[0]?nums[1]:dp[0];
for(int i=2;i<nums.size();i++)
{
dp[i]=nums[i]+dp[i-2]>dp[i-1]?nums[i]+dp[i-2]:dp[i-1];
}
return dp[nums.size()-1];
}
};
由于dp[i]的值只与dp[i-1]和dp[i-2]有关,因此可以用两个变量pre和prepre存储dp[i-1]和dp[i-2]的值,并不断更新,这样可以节省开辟dp[nums.size()]的空间!
代码:
class Solution {
public:
int rob(vector<int>& nums) {
if(nums.size()==1)
return nums[0];
int now=0;
int prepre=nums[0];
int pre=nums[1]>prepre?nums[1]:prepre;
for(int i=2;i<nums.size();i++)
{
now=nums[i]+prepre>pre?nums[i]+prepre:pre;
prepre=pre;
pre=now;
}
return pre;
}
};
好耶!