题目描述:
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。
示例 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 。
解答:
方法一:
方法一时典型地动态规划法,属于选或者不选的问题,具体到本题就是进或者不进某一家。通过一个数组info 保存从开始到某一户人家的最优解(能偷到的最大价值),那么接下来问题就是考虑进不进当前这一户,通过比较如果不进收益高,那么就不进。如果进收益高,那么就进。这样,历遍所有元素之后,便得到最优解,保存在数组的最后一个单元。这种方法是一种自底向上的方法,和《算法导论》中的钢条切割问题是类似的。
用时8ms,战胜了18%的cpp提交者。
class Solution {
public:
int rob(vector<int>& nums) {
if(nums.empty()) return 0;
int n=nums.size();
vector<int> info(n,0);
for(int i=0;i<n;++i)
{
if(i==0) info[i]=nums[i];
else if(i==1) info[i]=max(info[i-1],nums[i]);
else
{
info[i]=max(info[i-1],nums[i]+info[i-2]);
}
}
return info[n-1];
}
};
方法二:
方法二看起来明显笨重,也是动态规划的思想,用时小于1ms,在leetcode上显示0ms,战胜了100%的cpp提交者。这种方法的思路是用一个数组保存 info 保存信息,保存的是进入当前这户人家的情况下,可以得到的最大收益(偷盗东西最多)。注意,每次对应的都是已经进入了这户人家的条件下。最后在历遍info这个数组,找出其中的最大值即使答案。
我还是不太清楚为什么会比方法一快这么多,如果哪位大神知道,请指教。
class Solution {
public:
int rob(vector<int>& nums) {
int n=nums.size();
vector<int> info(n,0);
for(int i=0;i<n;++i)
{
if(i==0) info[i]=nums[i];
else
{
if(i-2>=0)
{
int q=0;
for(int j=i-2;j>=0;--j)
{
if(q<info[j]+nums[i])
q=info[j]+nums[i];
}
info[i]=q;
}
else
{
info[i]=nums[i];
}
}
}
int res=0;
for(int i=0;i<n;++i)
{
if(info[i]>res)
res=info[i];
}
return res;
}
};