LeetCode-337-打家劫舍III

本文介绍了如何使用深度优先搜索和记忆化技术解决LeetCode题目337——打家劫舍III。通过三种方法对比,包括暴力递归、哈希表记忆化和状态转移数组,展示了如何避免重复计算,优化算法效率。

LeetCode-337-打家劫舍III

在这里插入图片描述

思路

用爷爷,儿子(2),孙子(4)来解释,由题意知道,相邻节点不能偷。那么可知最大偷法只有2种:
爷爷+孙子(4)偷或者儿子(2)偷
方法一:暴力递归

int res1 = root.val + rob(root.left.left) + rob(root.left.right) + rob(root.right.left) + rob(root.right.right)
int res2 = rob(root.left) + rob(root.right);
挑选一个钱数多的方案则
int result = Math.max(res1, res2);

方法二:记忆化搜索
发现当我们递归计算爷爷节点时,其实也算了儿子和孙子节点。当儿子作为根节点时又重复计算。其实可以使用哈希表保存计算结果。当将要发生重复计算时,直接返回即可。

HashMap<TreeNode, Integer> memo = new HashMap<>();
return robInternal(root, memo);

方法三:
每个节点可选择偷或者不偷两种状态
当前节点选择偷时,那么两个孩子节点就不能选择偷了
当前节点选择不偷时,两个孩子节点只需要拿最多的钱出来就行(两个孩子节点偷不偷没关系)
我们使用一个大小为 2 的数组来表示 int[] res = new int[2]
0 代表不偷,1 代表偷

/*任何一个节点能偷到的最大钱的状态可以定义为
当前节点选择不偷:当前节点能偷到的最大钱数 = 左孩子能偷到的钱 + 右孩子能偷到的钱
当前节点选择偷:当前节点能偷到的最大钱数 = 左孩子选择自己不偷时能得到的钱 + 右孩子选择不偷时能得到的钱 + 当前节点的钱数
表示为公式如下*/

root[0] = Math.max(rob(root.left)[0], rob(root.left)[1]) + Math.max(rob(root.right)[0], rob(root.right)[1])
root[1] = rob(root.left)[0] + rob(root.right)[0] + root.val;

代码

//方法一(超时)
 public int rob(TreeNode root) {
        if(root==null)return 0;
        
        int res1=root.val;
        if(root.left!=null) res1+=rob(root.left.left)+rob(root.left.right);
        if(root.right!=null) res1+=rob(root.right.left)+rob(root.right.right);

        int res2=rob(root.left)+rob(root.right);
        
        return Math.max(res1,res2);
    }
//方法二
 public int rob(TreeNode root) {
    HashMap<TreeNode, Integer> memo = new HashMap<>();
    return robInternal(root, memo);
}

public int robInternal(TreeNode root, HashMap<TreeNode, Integer> memo) {
    if (root == null) return 0;
    if (memo.containsKey(root)) return memo.get(root);
    int money = root.val;

    if (root.left != null) {
        money += (robInternal(root.left.left, memo) + robInternal(root.left.right, memo));
    }
    if (root.right != null) {
        money += (robInternal(root.right.left, memo) + robInternal(root.right.right, memo));
    }
    int result = Math.max(money, robInternal(root.left, memo) + robInternal(root.right, memo));
    memo.put(root, result);
    return result;
}
//方法三
public int rob(TreeNode root) {
        int []res=helper(root);
        return Math.max(res[0],res[1]);
    }
    public int[] helper(TreeNode root){
        int []res=new int[2];
        if(root==null)return res;
        int []left=helper(root.left);
        int []right=helper(root.right);
        
        res[0]=Math.max(left[0],left[1])+Math.max(right[0],right[1]);
        res[1]=left[0]+right[0]+root.val;

        return res;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值