你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装
有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。
示例 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 。
-
分析:
动态规划做的多了,逐渐感觉,对于最值问题,都可以,先往动态规划的方向想一想; 现在看来,dp做的就是以下几件事: 1. 找最值判断,max/min (若不是那就别往动态规划想了) 2. 判断最优子结构,即划分集合,{...,a}和{...,a,b}进行比较,加入b前的集合有一个最值, 加入b后,利用{...,a}集合的最值,判断加入b后的集合最值情况,要利用{...,a}集合的最值 3. 构造并利用dp表记录各集合下的最值 本题目: 1. 因为不能相连,所以对于i位置的最大累计和,应当是nums[i]+max{nums[i],0<=i<=i-2}, 2. 对于集合{...,nums[i]},除nums[i-1]外,最大累计和是nums[i] 3. 所以集合集合{...,nums[i]}的最大累计和应当是:max{nums[i-1],nums[i-2]} 递推公式:
d p [ i ] = { n u m s [ i ] i = 0 m a x { n u m s [ i − 1 ] , n u m s [ i ] } i = 1 m a x { d p [ i − 1 ] , d p [ i − 2 ] + n u m s [ i ] } i > 0 dp[i]=\left\{ \begin{aligned} &nums[i] & i=0 \\ &max\{nums[i-1],nums[i]\}&i=1\\ &max\{dp[i-1],dp[i-2]+nums[i]\} & i>0\\ \end{aligned} \right. dp[i]=⎩⎪⎨⎪⎧nums[i]max{nums[i−1],nums[i]}max{dp[i−1],dp[i−2]+nums[i]}i=0i=1i>0
- code
package main
import "fmt"
func rob(nums []int) int {
s:=len(nums)
if s==0{
return 0
}else if s==1{
return nums[0]
}
for i:=2;i<s;i++{
if nums[i-2]>nums[i-1]{
nums[i-1]=nums[i-2]
}
nums[i]+=nums[i-2]
}
if nums[s-2]>nums[s-1]{
nums[s-1]=nums[s-2]
}
return nums[s-1]
}
func main(){
fmt.Println(rob([]int{2,7,9,3,1}))
}