题目描述:
你是一个专业的强盗,计划抢劫沿街的房屋。每间房都藏有一定的现金,阻止你抢劫他们的唯一的制约因素就是相邻的房屋有保安系统连接,如果两间相邻的房屋在同一晚上被闯入,它会自动联系警方。
给定一个代表每个房屋的金额的非负整数列表,确定你可以在没有提醒警方的情况下抢劫的最高金额。
方法一、 暴力搜索:
思路:文中给出不能连续抢两家,因此假设从最后一个房屋开始抢,最后一个房屋为idx。将原问题分割成子问题,子问题的最优决策可以导出原问题的最优决策。现有两种可能情况,当前房屋抢和当前房屋不抢。若当前房屋抢,则下一房屋不能抢;若当前房屋不抢,则下一房屋可抢;选出这两种情况的最大值,递归执行,直到idx<0。
class Solution {
public int solve(int idx,int[] nums){
if(idx<0){
return 0;
}
return Math.max(nums[idx]+solve(idx-2,nums),solve(idx-1,nums));
}
public int rob(int[] nums) {
return solve(nums.length-1,nums);
}
}
方法二、动态规划
在递归方法中,存在大量的重复计算问题:
假如抢第n-1家,就得计算n-3,n-4,n-5,…
n-1 -> (n-3,n-4,n-5,…)
假如抢第n-2家,就得计算n-3,n-4,…
n-2 -> (n-4,n-5,…)
因此,每一家都有两种可能可能,抢或者不抢。则该算法的时间复杂度为:O(2n)。这样就重复计算了很多,我们应该找到方法避免重复计算,每个值的计算应该保存下来,当下次被需要直接拿来用。这就是去冗余,用采用空间换时间的方法。因此当n-1房屋的最优解算过后,就能推导出n房屋的最优解。这就是动态规划的思想。(两点:最优子结构、去冗余)
动态规划:
- 本质是递归。原问题(N)->子问题(N-1)->原问题(N)
- 最优子结构
子问题最优决策可导出原问题最优决策
无后效性——当前的决策不影响后面的决策
自顶向下:先算最大的值,再往下进行。缺点:处理边界较多。
class Solution {
public static int[] result;
public int solve(int idx,int[] nums){
if(idx<0){
return 0;
}
if(result[idx]>=0){
return result[idx];
}
result[idx] = Math.max(nums[idx]+solve(idx-2,nums),solve(idx-1,nums));
return result[idx];
}
public int rob(int[] nums) {
result = new int[nums.length];
for(int i=0;i<nums.length;++i){
result[i] = -1;
}
return solve(nums.length-1,nums);
}
}
自底向上:
class Solution {
public int rob(int[] nums) {
int[] result;
if(nums.length==0)
return 0;
result=new int[nums.length];
result[0]=nums[0];
result[1]=Math.max(nums[0],nums[1]);
for (int idx=2;idx<nums.length;++idx){
result[idx] = Math.max(nums[idx]+result[idx-2],result[idx-1]);
}
return result[nums.length-1];
}
}