-
讲解观后感
- 可以将dp数组设置为偷到第i个家(从1开始)时能获得的最高金额。就可以只初始化
dp[1]了。
-
解题代码
- 从0开始
-
func rob(nums []int) int {
n := len(nums)
if n<2 {
return nums[0]
}
if n==2 {
return max(nums[0], nums[1])
}
dp := make([]int, n)
dp[0] = nums[0]
dp[1] = max(nums[0], nums[1])
for i:=2;i<n;i++ {
dp[i] = max(dp[i-2]+nums[i],dp[i-1] )
}
return dp[n-1]
}
func max(x int, y int) int {
if x>y {
return x
} else {
return y
}
}
- 从1开始
-
func rob(nums []int) int {
n := len(nums)
dp := make([]int, n+1)
dp[1] = nums[0]
for i := 2; i <= n; i++ {
dp[i] = max(dp[i-1], dp[i-2] + nums[i-1])
}
return dp[n]
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
-
213打家劫舍II
- 代码随想录 (programmercarl.com)
-
第一印象
- 总体方法还是动态规划,之后要加入初始位置和首尾关系的讨论。
-
讲解观后感
- 卡尔讨论了三种不同的首尾包含情况。但我在自己做题的过程中,直接只讨论分别不包括首尾的情况也成功ac了。
-
解题代码
-
func rob(nums []int) int {
n := len(nums)
if n<2 {
return nums[0]
}
dp := make([]int, n+1)
dp[1] = nums[0]
for i := 2; i < n; i++ {// dp[i]表示偷到第i家(从1开始)能够偷得的最大金额
dp[i] = max(dp[i-1], dp[i-2] + nums[i-1])
}
ans1 := dp[n-1]
dp[1] = 0
dp[2] = nums[1]
for j:=3;j<n+1;j++ {
dp[j] = max(dp[j-1], dp[j-2] + nums[j-1])
}
ans2 := dp[n]
return max(ans1, ans2)
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
-
337打家劫舍III
- 代码随想录 (programmercarl.com)
-
第一印象
- 在树形结构中,警报的情况变成了在同一个通向叶子节点的路径中来判断。并且会造成父节点对兄弟节点的影响。不能简单的分层讨论。嘴和期望得到的数值要综合讨论所有分支的情况,那也许应该选择后序遍历。
-
讲解观后感
- 本题一定是要后序遍历,因为通过递归函数的返回值来做下一步计算。
- 我们要记录当前节点偷与不偷所得到的最大金钱。所以要用一个长度2的数组来记录
- 遇到空节点直接返回
[]int{0, 0}(后序遍历的终止条件,同时相当于dp数组的起始值)
- 状态转移公式 (同时相当于遍历过程的处理) :
-
// 考虑去偷当前的屋子
robCur := cur.Val + left[0] + right[0]
// 考虑不去偷当前的屋子
notRobCur := max(left[0], left[1]) + max(right[0], right[1])
-
解题代码
-
func rob(root *TreeNode) int {
res := robTree(root)
return max(res[0], res[1])
}
func robTree(cur *TreeNode) []int {
if cur == nil {
return []int{0, 0}
}
left := robTree(cur.Left)
right := robTree(cur.Right)
robCur := cur.Val + left[0] + right[0]
notRobCur := max(left[0], left[1]) + max(right[0], right[1])
return []int{notRobCur, robCur}
}
func max(a, b int) int {
if a > b {
return a
}
return b
}