LeetCode_BinaryTree_337. House Robber III 打家劫舍 III【动态规划】【Java】【中等】

本文介绍了如何利用后序遍历和动态规划解决LeetCode上的打家劫舍III问题。小偷需要在不触发警报的情况下最大化盗窃金额,而房屋排列成二叉树结构。通过递归实现的后序遍历,可以有效地计算出每个节点的最大盗窃价值,并最终确定整个树的最大盗窃总额。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一,题目描述

英文描述

中文描述

示例与说明

二,解题思路

三,AC代码

Java

四,解题过程

第一搏

第二搏


 

一,题目描述

英文描述

The thief has found himself a new place for his thievery again. There is only one entrance to this area, called root.

Besides the root, each house has one and only one parent house. After a tour, the smart thief realized that all houses in this place form a binary tree. It will automatically contact the police if two directly-linked houses were broken into on the same night.

Given the root of the binary tree, return the maximum amount of money the thief can rob without alerting the police.

中文描述

小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为 root 。

除了 root 之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果 两个直接相连的房子在同一天晚上被打劫 ,房屋将自动报警。

给定二叉树的 root 。返回 在不触动警报的情况下 ,小偷能够盗取的最高金额 。

示例与说明

 

 

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/house-robber-iii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

二,解题思路

参考官方题解@力扣官方题解【打家劫舍 III】

后序遍历+动态规划,后序遍历指明了动态规划的转移顺序。

声明一个长度为2的数组记录动态规划过程中产生的值,其中位置0表示不选择当前节点,1表示选择当前节点;

先遍历左子树得到左子树的状态数组leftTree,再遍历右子树得到右子树的状态数组rightTree,最后可以得到当前节点的状态数组ans

不选当前节点,左右子树节点可选可不选(取两种方案最大值): 

  • ans[0] = Math.max(leftTree[0], leftTree[1]) + Math.max(rightTree[0], rightTree[1])

选择当前节点,左右两子节点均不能选择: 

  • ans[1] = root.val + leftTree[0] + rightTree[0]

三,AC代码

Java

class Solution {

    public int rob(TreeNode root) {
        int[] ans = dfs(root);
        return Math.max(ans[0], ans[1]);
    }
    public int[] dfs(TreeNode root) {
        if (root == null) return new int[]{0, 0};
        int[] leftTree = dfs(root.left);
        int[] rightTree = dfs(root.right);
        int[] ans = new int[2];
        
        ans[1] = root.val + leftTree[0] + rightTree[0];// 选择root节点,则左右子树节点不能被选中
        ans[0] = Math.max(leftTree[0], leftTree[1]) + Math.max(rightTree[0], rightTree[1]);// 不选root节点,左右子树节点可选可不选(取两种方案最大值)
        return ans;
    }
}

四,解题过程

第一搏

后序遍历 + 双hash表(分别记录是否选择当前节点下的情况)

class Solution {
    Map<TreeNode, Integer> choose = new HashMap<>();
    Map<TreeNode, Integer> notChoose = new HashMap<>();
    public int rob(TreeNode root) {
        choose.put(null, 0);
        notChoose.put(null, 0);
        dfs(root);
        return Math.max(choose.get(root), notChoose.get(root));
    }
    public void dfs(TreeNode root) {
        if (root == null) return;
        dfs(root.left);
        dfs(root.right);

        int ans = 0;
        ans = root.val + notChoose.get(root.left) + notChoose.get(root.right);
        choose.put(root, ans);

        int maxLeft = Math.max(choose.get(root.left), notChoose.get(root.left));
        int maxRight = Math.max(choose.get(root.right), notChoose.get(root.right));
        ans = maxLeft + maxRight;
        notChoose.put(root, ans);
    }
}

第二搏

注意到后序遍历过程中,只会用到当前节点左右两子树节点对应的状态,因此递归返回值可以用大小为2的数组代替,其中位置0表示不选择当前节点,1表示选择当前节点。

这样递归过程将会变得更加简洁

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值