golang力扣leetcode 337.打家劫舍III

简介: golang力扣leetcode 337.打家劫舍III

337.打家劫舍III

337.打家劫舍III

题解

题目:给一个二叉树,相邻两个节点不能同时选,问能选的节点累加最大的值

思路:

暴力递归 - 最优子结构

1.既然相邻不能选,那么
method1:选当前节点以及4个孙子节点
method2:不选当前节点,选两个孩子节点
返回max(method1, method2)

记忆化 - 解决重复子问题

爷爷节点会计算孙子节点
父节点也会计算孙子节点
存在重复子问题,用记忆化解决

动态规划

即使用了记忆化剪枝,还是会超时,所以只能用动态规划了
选择当前节点:当前节点的值+不选左孩子节点+不选右孩子节点
selected[root] = root.Val + notSelected[root.Left] + notSelected[root.Right]
不选当前节点 = max(选左孩子,不选左孩子)+max(选右孩子,不选右孩子)
notSelected[root] = max(selected[root.Left], notSelected[root.Left]) + max(selected[root.Right], notSelected[root.Right])

优化

我们发现递归回去的时候,无论是selected[root]还是notSelected[root]
他们的状态始终与notSelected[root.Left] ,notSelected[root.Right],selected[root.Left],selected[root.Right]
这4个有关
所以我们可以定义一个长为2的数组,arr[0]代表选,arr[1]代表不选
在每次递归的时候返回给上一级,节省空间复杂度

代码

TLE 暴力递归 - 最优子结构

func rob(root *TreeNode) int {
  if root == nil {
    return 0
  }
  method1 := root.Val
  if root.Left != nil {
    method1 += rob(root.Left.Left) + rob(root.Left.Right)
  }
  if root.Right != nil {
    method1 += rob(root.Right.Left) + rob(root.Right.Right)
  }
  method2 := rob(root.Left) + rob(root.Right)
  return max(method1, method2)
}
func max(i, j int) int {
  if i > j {
    return i
  }
  return j
}

TLE 记忆化 - 解决重复子问题

func rob(root *TreeNode) int {
  mp := map[*TreeNode]int{}
  var dfs func(root *TreeNode) int
  dfs = func(root *TreeNode) int {
    if _, ok := mp[root]; ok {
      return mp[root]
    }
    if root == nil {
      return 0
    }
    method1 := root.Val
    if root.Left != nil {
      method1 += rob(root.Left.Left) + rob(root.Left.Right)
    }
    if root.Right != nil {
      method1 += rob(root.Right.Left) + rob(root.Right.Right)
    }
    method2 := rob(root.Left) + rob(root.Right)
    mp[root] = max(method1, method2)
    return mp[root]
  }
  return dfs(root)
}
func max(i, j int) int {
  if i > j {
    return i
  }
  return j
}

动态规划

func rob(root *TreeNode) int {
  selected := map[*TreeNode]int{}
  notSelected := map[*TreeNode]int{}
  var dfs func(root *TreeNode)
  dfs = func(root *TreeNode) {
    if root == nil {
      return
    }
    dfs(root.Left)
    dfs(root.Right)
    selected[root] = root.Val + notSelected[root.Left] + notSelected[root.Right]
    notSelected[root] = max(selected[root.Left], notSelected[root.Left]) + max(selected[root.Right], notSelected[root.Right])
  }
  dfs(root)
  return max(selected[root], notSelected[root])
}
func max(i, j int) int {
  if i > j {
    return i
  }
  return j
}

动态规划-优化

func rob(root *TreeNode) int {
  var dfs func(root *TreeNode) [2]int
  dfs = func(root *TreeNode) [2]int { //0选 1不选
    if root == nil {
      return [2]int{0, 0}
    }
    l := dfs(root.Left)
    r := dfs(root.Right)
    selected := root.Val + l[1] + r[1]
    notSelected := max(l[0], l[1]) + max(r[0], r[1])
    return [2]int{selected, notSelected}
  }
  val := dfs(root)
  return max(val[0], val[1])
}
func max(i, j int) int {
  if i > j {
    return i
  }
  return j
}
目录
相关文章
|
3月前
|
程序员 C语言
【C语言】LeetCode(力扣)上经典题目
【C语言】LeetCode(力扣)上经典题目
|
3月前
|
索引
力扣(LeetCode)数据结构练习题(3)------链表
力扣(LeetCode)数据结构练习题(3)------链表
106 0
|
3月前
力扣(LeetCode)数据结构练习题(2)
力扣(LeetCode)数据结构练习题(2)
35 0
|
3月前
|
存储
力扣(LeetCode)数据结构练习题
力扣(LeetCode)数据结构练习题
62 0
|
5月前
|
移动开发 Python
【Leetcode刷题Python】337. 打家劫舍 III
LeetCode 337题 "打家劫舍 III" 的Python解决方案,使用递归和动态规划计算小偷在二叉树结构的房屋中不触发警报的情况下能够盗取的最高金额。
54 1
【Leetcode刷题Python】337. 打家劫舍 III
|
5月前
|
存储 算法 Java
LeetCode经典算法题:打家劫舍java详解
LeetCode经典算法题:打家劫舍java详解
83 2
|
4月前
|
Go
Golang语言之管道channel快速入门篇
这篇文章是关于Go语言中管道(channel)的快速入门教程,涵盖了管道的基本使用、有缓冲和无缓冲管道的区别、管道的关闭、遍历、协程和管道的协同工作、单向通道的使用以及select多路复用的详细案例和解释。
147 4
Golang语言之管道channel快速入门篇
|
4月前
|
Go
Golang语言文件操作快速入门篇
这篇文章是关于Go语言文件操作快速入门的教程,涵盖了文件的读取、写入、复制操作以及使用标准库中的ioutil、bufio、os等包进行文件操作的详细案例。
75 4
Golang语言文件操作快速入门篇
|
4月前
|
Go
Golang语言之gRPC程序设计示例
这篇文章是关于Golang语言使用gRPC进行程序设计的详细教程,涵盖了RPC协议的介绍、gRPC环境的搭建、Protocol Buffers的使用、gRPC服务的编写和通信示例。
121 3
Golang语言之gRPC程序设计示例
|
4月前
|
安全 Go
Golang语言goroutine协程并发安全及锁机制
这篇文章是关于Go语言中多协程操作同一数据问题、互斥锁Mutex和读写互斥锁RWMutex的详细介绍及使用案例,涵盖了如何使用这些同步原语来解决并发访问共享资源时的数据安全问题。
101 4