【LeetCode】337. 打家劫舍 III

思路参考自王小二的题解

以下面的这棵树来说明
  a
 b  c 
d  e f  g
对于这棵树,我们用爷爷-两个孩子-四个孙子来说明
问题的状态:
爷爷节点获取到最大的偷钱数是多少呢?
1、首先要明确相邻的节点不能偷,也就是爷爷选择偷,儿子就不能偷了,但是孙子可以偷
2、二叉树只有左右两个孩子,一个爷爷最多2个儿子,4个孙子
根据以上条件,可以得出单个节点的钱该怎么算:
4个孙子的偷的钱+爷爷的钱VS两个儿子偷的钱
哪个组合钱多,就能成为当前节点能偷的最大钱数,这就是动态规划里的最优子结构
由于是二叉树,这里可以选择计算所有子节点
4个孙子投的钱加上爷爷的钱如下
int method1=root.val+rob(root.left.left)+rob(root.left.right)+rob(root.right.left)+rob(root.right.right)
两个儿子偷的钱如下
int method2=rob(root.left)+rob(root.right);
挑选一个钱数多的方案则
int result=Math.max(method1,method2)
编写代码如下


class Solution {
public:
	int rob(TreeNode* root) {
		if (root == nullptr) return 0;
		int money = root->val;
		if (root->left != nullptr) {//左孩子不为空,把孙子的钱抢了
			money += rob(root->left->left) + rob(root->left->right);
		}
		if (root->right!=nullptr)//右孩子不为空,把孙子的钱抢了
		{
			money + rob(root->right->left) + rob(root->right->right);
		}
		return max(money, rob(root->left) + rob(root->right));//抢孙子及爷爷的钱和抢两个儿子的钱进行比较
	}
};

记忆化优化
本题记忆化需要拿哈希表来当缓存,也是自己第一次遇到这种情况,大开眼界
对于上述思想进行编码,无法通过案例,因此,采用记忆化的方式,减少中间的计算量。由于二叉树不适合拿数组当缓存,需要使用哈希表来存储结果,TreeNode当做key,能偷的钱当做value

优化后的代码如下:

class Solution {
public:
	int rob(TreeNode* root) {
		unordered_map<TreeNode*, int> dp;
		return robMemory(root, dp);
	}
	int robMemory(TreeNode* root, unordered_map<TreeNode*, int>& dp) {
		if (root == nullptr) return 0;
		if (dp.find(root) != dp.end()) return dp[root];//已存在
		int money = root->val;
		if (root->left != nullptr) {
			money += robMemory(root->left->left, dp) + robMemory(root->left->right, dp);
		}
		if (root->right != nullptr)
		{
			money += robMemory(root->right->left, dp) + robMemory(root->right->right, dp);
		}
		money = max(money, robMemory(root->left, dp) + robMemory(root->right, dp));
		dp.insert({ root,money });//更新未存储过的dp键值对
		return dp[root];
	}
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值