这是我参与2022首次更文挑战的第17天,活动详情查看:2022首次更文挑战
打家劫舍Ⅲ
小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为 root 。
除了 root 之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果 两个直接相连的房子在同一天晚上被打劫 ,房屋将自动报警。
给定二叉树的 root 。返回 在不触动警报的情况下 ,小偷能够盗取的最高金额 。
示例 1:
输入: root = [3,2,3,null,3,null,1]
输出: 7
解释: 小偷一晚能够盗取的最高金额 3 + 3 + 1 = 7
示例 2:
输入: root = [3,4,5,1,3,null,1]
输出: 9
解释: 小偷一晚能够盗取的最高金额 4 + 5 = 9
提示:
树的节点数在 [1, 104] 范围内
0 <= Node.val <= 104
题解
算法一:动态规划(Java)
这道题目和打家劫舍、打家劫舍II 也是如出一辙,只不过这个换成了树。
如果对树的遍历不够熟悉的话,那本题就有难度了。
对于树的话,首先就要想到遍历方式,前中后序(深度优先搜索)还是层序遍历(广度优先搜索)。
本题一定是要后序遍历,因为通过递归函数的返回值来做下一步计算。
与打家劫舍、打家劫舍II 一样,关键是要讨论当前节点抢还是不抢。
如果抢了当前节点,两个孩子就不能动,如果没抢当前节点,就可以考虑抢左右孩子(注意这里说的是“考虑”)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int rob(TreeNode root) {
if (root == null) {
return 0;
}
int[] res = rob3Helper(root);
return Math.max(res[0], res[1]);
}
public int[] rob3Helper(TreeNode root) {
if (root == null) {
return new int[]{0, 0};
}
int[] left = rob3Helper(root.left);
int[] right = rob3Helper(root.right);
int select = root.val + left[0] + right[0];
int noSelect = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
return new int[]{noSelect, select};
}
}
时间复杂度:O(N)
空间复杂度:O(logN)
算法一:动态规划(Go)
思路同上
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func rob(root *TreeNode) int {
traverse(root)
return root.Val
}
func traverse(root *TreeNode) {
if nil == root {
return
}
traverse(root.Left)
traverse(root.Right)
left, right := 0, 0 //左右子树的值
leftNext, rightNext := 0, 0 //左右子树的子树
if nil != root.Left {
left = root.Left.Val
if nil != root.Left.Left {
leftNext += root.Left.Left.Val
}
if nil != root.Left.Right {
leftNext += root.Left.Right.Val
}
}
if nil != root.Right {
right = root.Right.Val
if nil != root.Right.Left {
rightNext += root.Right.Left.Val
}
if nil != root.Right.Right {
rightNext += root.Right.Right.Val
}
}
//改写root值,代表dp,(根+左右子树的子树和 与 根左右子树和 的最大值)与(左子树的子树和+右子树 与 右子树的子树和+左子树的最大值)的最大值
root.Val = max(max(leftNext+rightNext+root.Val, left+right), max(leftNext+right, rightNext+left))
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
时间复杂度:O(N)
空间复杂度:O(logN)