文章目录
前言
提示:打家劫舍问题是个很经典的动态规划问题,类似的还有背包问题、凑零钱问题等等
这类问题大部分都是择优选择,如:
res = max(选择打劫,选择不打劫)
一、动态规划 LeetCode. 198. 打家劫舍问题描述
二、动态规划 LeetCode. 198. 打家劫舍问题解法
核心代码: res = max(打劫, 不打劫)
核心代码: res = max(打劫, 不打劫)
核心代码: res = max(打劫, 不打劫)
func rob(nums []int) int {
// 1, 方法1
return rob1(nums)
// 2, 方法2
// return rob2(nums)
}
func rob1(nums []int) int {
n := len(nums)
// 1, baseCase
if n ==0 {
return 0
}
if n == 1{
return nums[0]
}
var (
s = make([]int, n+1)
)
s[0] = 0
s[1] = nums[0]
for i:=1; i<n; i++{
// 核心代码一行:做选择 = max(选择打劫的结果, 不选择打劫的结果)
s[i+1] = getMax(s[i], s[i-1]+nums[i])
}
return s[n]
}
func rob2(nums []int) int {
n := len(nums)
// 1, baseCase
if n ==0 {
return 0
}
if n == 1{
return nums[0]
}
// 2, 状态
// 用s0,s1,s2可以优化空间,这点跟`斐波那契数列`的优化一样,因为不需要记住全部的状态,只需要用3个变量表示中间状态
var s0 = 0
var s1 = nums[0]
var s2 = 0
for i:=1; i<n; i++{
// 做选择,sel = max(打劫, 不打劫)
s2 = getMax(s1, s0 + nums[i])
s0 = s1
s1 = s2
}
return s2
}
func getMax(a,b int)int{
if a>b{
return a
}
return b
}
三、动态规划 LeetCode 213. 打家劫舍 II
核心思想:将圈圈拆开,拆成2个LeetCode.198 打家劫舍问题
func rob(nums []int) int {
n := len(nums)
if n==0{
return 0
}else if n==1{
return nums[0]
}
// 打劫第一次,打劫第二次
return getMax( robHelp(nums[0:n-1]), robHelp(nums[1:n]) )
}
func robHelp(nums []int) int{
n := len(nums)
if n==0{
return 0
}else if n==1{
return nums[0]
}
var (
s0 = 0
s1 = nums[0]
s2 = 0
)
for i:=1; i<n; i++{
// 核心代码 res = max(打劫,不打劫)
s2 = getMax(s1, s0 + nums[i])
s0 = s1
s1 = s2
}
return s2
}
func getMax(a,b int) int {
if a>b{
return a
}
return b
}