你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。
示例 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 。
这题用动态规划。用递归可以,但是会超时,最好的方法就是动态规划。
但是建议会动态规划之前要先会递归。因为动态规划说白了就是优化暴力解。
用空间换时间,因为递归存在大量的重复计算,往往一个步骤要重复算很多次,明明算过一次了,但是因为没有保存,却总是要重复来计算,这就浪费了太多的时间。
动态规划就是遇见一个步骤,用空间保留了它的结果,下次要用的时候就不需要计算了。
经典的动态规划有背包问题,最长子序列等题目,以后我会更博写出来。
这题是个简单的入门动态规划题目。在用动态规划我们可以先想一下递归该怎么写?
我们考虑一下。遇到一个店的时候我们有两种决策:不抢和抢。
不抢我们不需要代价,抢了的代价就是下一家不可以抢了。
递归是肯定需要一个出口的,这个出口我们用index 来表示。
那现在我们来考虑
抢了以后我们能得到什么?那家店的财富,失去什么?下一家的抢劫权。
不抢就无损失也无得到了。
我们先用递归来写。
#include<stdio.h>
#include<string.h>
#define LENGTH(a) (sizeof(a)/sizeof(a[0]))
#define max(a,b) ((a)>(b)?(a):(b))
int ans;
int rob(int* nums, int numsSize)
{
return dfs(numsSize,nums,numsSize);
}
int dfs(int index, int* num, int numsSize)
{
if(index < 0)
return 0;
return max(num[index] + dfs(index - 2,num,numsSize) ,dfs(index - 1,num,numsSize));
}
int main()
{
int i;
int nums[] = {2,7,9,3,1};
int numsSize = LENGTH(nums);
ans = rob(nums,numsSize);
printf("%d",ans);
return 0;
}
这种写法肯定得超时啊,那怎么办,空间换时间,用数组来记录本来每一次递归得到的值。
注意动态规划要注意数组的初始化。
以下是动态规划的写法,在leetcode上通过。
#include<stdio.h>
#define max(a,b) ((a)>(b)?(a):(b))
#define LENGTH(a) (sizeof(a)/sizeof(a[0]))
int rob(int* nums, int numsSize)
{
if(numsSize == 0)
return 0;
if(numsSize == 1)
return nums[0];
int res[numsSize + 1];
res[0] = nums[0];
res[1] = max(nums[0] , nums[1]);
int i;
for(i=2; i<numsSize; i++)
{
res[i] = max(res[i- 2] + nums[i],res[i - 1]);
}
return res[i - 1];
}
int main()
{
int nums[] = {2,7,9,3,1};
int numsSize = LENGTH(nums);
int max = rob(nums,numsSize);
printf("%d",max);
return 0;
}