1、问题描述
假设你是一个小偷,计划盗窃沿街的房屋,每个房屋都藏有一定数量的现金,影响你盗窃的唯一制约是每两间相邻的房屋装有相互连通的报警装置,如果你盗窃了两间相邻的房屋就会触发报警装置。
给定一个非负整数数组表示每个房屋藏有的现金金额。计算在不触动报警装置的情况下,能盗窃到的最大金额。
例子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 。
2、解题思路
方法1:暴力法。最简单的方法是穷举所有的盗窃方案,然后找到对应的最大盗取金额。
问题的解空间树如下所示(以例1为例说明):
只要使用深度优先搜索这颗树即可,伪代码如下所示:
#dfs(current, len, curcash, maxcash, nums):
*if(current + 2 < len):
#maxcash = max(curcash,maxcash)
#return
*for(next = current + 2; next < len; next++):
#curcash += nums[next]
#dfs(next, len, curcash, maxcash, nums)
#curcash -= nums[next]
注意,这种方法的时间复杂度并不是指数级的,因为解空间树的分支数量为 ( n − 2 ) + ( n − 3 ) + . . . + 1 = ( n − 1 ) ( n − 2 ) 2 (n-2)+(n-3)+...+1=\frac{(n-1)(n-2)}{2} (n−2)+(n−3)+...+1=2(n−1)(n−2),因此时间复杂度 O ( n 2 ) O(n^2) O(n2),空间复杂度为递归的深度,为 O ( n ) O(n) O(n)。
方法2:动态规划1. 从上面的解空间树可以看出,存在最优子结构,例如,盗窃的最后一个房屋为4号房屋所能获得最大金额等于盗窃的最后一个房屋为2号房屋所能获得最大金额+4号房屋的金额,与盗窃的最后一个房屋为1号房屋所能获得的最大金额+4号房屋的金额,这两者之间的最大值。
根据这一个发现,我们采用与LIS相同的动态规划思路来解决这个问题:
(1)定义状态
d p [ i ] dp[i] dp[i]:盗窃的最后一个房屋为第 i i i号房子所能获得的最大金额;
(2)状态转移
d p [ i ] = m a x { d p [ i ] , d p [ j ] + n u m s [ i ] } , j ∈ [ 0 , i − 2 ] dp[i] =max\{dp[i],dp[j] + nums[i] \},j\in[0,i-2] dp[i]=max{
dp[i],dp[j]+nums[i]},j∈[0,i−2]
盗窃的最后一个房屋为第 i i i号房所能获得的最大金额等于以前 i − 2 i-2 i−2个房子中的第 j j j号房屋能获得的金额的最大值加上第 i i i号房屋所藏的金额。
(3)确定初始
d p [ i ] = n u m s [ i ] , i < 2 dp[i] = nums[i], i<2