你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。
示例 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. 如果我用dp[i]来表示第i家店偷得决策导致的后果,nums[i]表示第i家店的价值,那么dp[i-2]+nums[i])表示“偷”了第i家店的后果称为决策1后果;
2. dp[i-1]就表示没偷得决策导致的后果称为决策2后果
那么我只需要每次去比较max(决策1后果,决策2后果)
下面给出Ac代码(C语言实现)
int max(int a,int b)
{
return a>b ? a:b;
}
int rob(int* nums, int numsSize) {
int *dp;
int i=0;
dp = (int *)malloc(numsSize*sizeof(int));
if(dp!=NULL)
{
dp[0]=nums[0];
dp[1]=max(nums[0],nums[1]);
for(i=2;imax(nums[i]+dp[i-2],dp[i-1]);
}
return dp[numsSize-1];
}
return 0;
}
关于强盗问题的第二版本是这样的
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。
示例 1:
输入: [2,3,2]
输出: 3
解释: 你不能先偷窃 1 号房屋(金额 = 2) ,然后偷窃 3号房屋 (金额 = 2), 因为他们是相邻的。
示例 2:
输入: [1,2,3,1]
输出: 4
解释: 你可以先偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。
这是个环形的问题,一般来说有个较为巧妙的办法是将环拆成两个部分
精彩之处是我们将一个环形的数组拆成从0到numsSize-2和1到numsSize-1两个子数组,那么就可以完美的避免了首尾都被选中的尴尬局面,这样问题就成了两个dp问题了最后我们记录比较两个子问题的最优解谁更优,就得出了整个大问题的全局最优解了
下面给出全网速度最快的AC代码
int max(int a,int b)
{
return a>b ?a:b;
}
int rob(int* nums, int numsSize) {
int *dp;
int i=0;
dp=(int *)malloc(numsSize*sizeof(int));
if(numsSize==0) return 0;
if(numsSize==1) return nums[0];
if(numsSize==2) return max(nums[0],nums[1]);
else
{
dp[0]=nums[0];
dp[1]=max(nums[0],nums[1]);
for(i=2;imax(dp[i-2]+nums[i],dp[i-1]);
}
int tmp1 = dp[numsSize-2];
dp[1]=nums[1];
dp[2]=max(nums[1],nums[2]);
for(i=3;imax(dp[i-2]+nums[i],dp[i-1]);
}
int tmp2 = dp[numsSize-1];
return max(tmp1,tmp2);
}
return 0;
}