leetcode337. House Robber III

题目:题目链接
思路:题目就是说选了root,就不能选root->left和root->right。那么很像dp是吧,那就来吧。

方法一 自己想的dp

来来来兄弟们,我有个非常好懂的方法,这里空白很多可以写下。
令dp[root]为以root为根节点的树的最大权值和。那么状态转移方程是啥?
首先如果不选择root的话,
d p [ r o o t ] = d p [ r o o t − > l e f t ] + d p [ r o o t − > r i g h t ] dp[root] = dp[root->left]+dp[root->right] dp[root]=dp[root>left]+dp[root>right]
也就是说你如果不选root的话,其实就相当于选择其左右结点的dp值。因为不选root就可以选其左右结点嘛。然后又因为左右结点可以都选,那么肯定是两者的和。

如果选root呢?咋整?选了root就不能选其左右结点嘛,但是可以选择左右结点的左右结点啊。对不对,翻译一下:
d p [ r o o t ] = d p [ r o o t − > l e f t − > l e f t ] + d p [ r o o t − > l e f t − > r i g h t ] + d p [ r o o t − > r i g h t − > l e f t ] + d p [ r o o t − > r i g h t − > r i g h t ] + r o o t − > v a l dp[root]=dp[root->left->left]+dp[root->left->right]+dp[root->right->left]+dp[root->right->right]+root->val dp[root]=dp[root>left>left]+dp[root>left>right]+dp[root>right>left]+dp[root>right>right]+root>val
仔细再想想看是不是这么个理。可以结合题中所给的例子体会下。
那么结合一下就是取两者的最大值嘛:
d p [ r o o t ] = m a x ( d p [ r o o t − > l e f t ] + d p [ r o o t − > r i g h t ] , ( d p [ r o o t − > l e f t − > l e f t ] + d p [ r o o t − > l e f t − > r i g h t ] + d p [ r o o t − > r i g h t − > l e f t ] + d p [ r o o t − > r i g h t − > r i g h t ] + r o o t − > v a l ) ) dp[root] = max(dp[root->left]+dp[root->right],(dp[root->left->left]+dp[root->left->right]+dp[root->right->left]+dp[root->right->right]+root->val)) dp[root]=max(dp[root>left]+dp[root>right],(dp[root>left>left]+dp[root>left>right]+dp[root>right>left]+dp[root>right>right]+root>val))
状态转移方程写出来了,我们就可以上手了,但是注意要使用记忆化dp哦,不然会tle,因为重复计算太多了。
看代码吧:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
	unordered_map<TreeNode*, int>dp;
	int dfs(TreeNode* root) {//找到dp[root],也就是以root为根节点的树,其最大权值和。
		if (!root) return dp[root] = 0;//空结点就是0
		if (dp[root] != 0) return dp[root];//记忆化dp,找过了就不重复了,不然会tle的。
		return  dp[root] = max(dfs(root->left) + dfs(root->right),
			root->val + ((root->left) ? (dfs(root->left->left) + dfs(root->left->right)) : 0) + ((root->right) ? (dfs(root->right->left) + dfs(root->right->right)) : 0)
		);//dp[root] = max(dp[root->left]+dp[root->right],dp[root->left->left]+dp[root->left->right]+dp[root->right->left]+dp[root->right->right]+root->val)
	}
	int rob(TreeNode* root) {
		dfs(root);
		return dp[root];
	}
};

感觉很精简有没有?很帅有没有!!

方法二 官方dp

官方解答特别清晰了哦,可以去看看官方题解
令f[root]为选择root情况下,该树的最大权值和,g[root]为不选择root情况下,该树的最大权值和。
那么如果选择root,其左右孩子都不能选,则
f [ r o o t ] = r o o t − > v a l + g [ r o o t − > l e f t ] + g [ r o o t − > r i g h t ] f[root]=root->val+g[root->left]+g[root->right] f[root]=root>val+g[root>left]+g[root>right]
这个不难理解。
如果不选呢?
g [ r o o t ] = m a x ( f [ r o o t − > l e f t ] , g [ r o o t − > l e f t ] ) + m a x ( f [ r o o t − > r i g h t ] , g [ r o o t − > r i g h t ] ) g[root] = max(f[root->left],g[root->left])+max(f[root->right],g[root->right]) g[root]=max(f[root>left],g[root>left])+max(f[root>right],g[root>right])
如果不选root,那么其左右孩子都可以选,那肯定是选择左右孩子中f,g最大的那个。
上代码:

class Solution {
public:
	unordered_map<TreeNode*, int>f, g;
	void dfs(TreeNode* root) {
		if (!root) return;
		dfs(root->left);//中序遍历查找每一个结点,获取其f,g。
		dfs(root->right);
		f[root] = root->val + g[root->left] + g[root->right];//选择root
		g[root] = max(f[root->left], g[root->left]) + max(f[root->right], g[root->right]);//不选择root
	}
	int rob(TreeNode* root) {
		dfs(root);
		return max(f[root], g[root]);//选最大的
	}
};

官方解答还是比较简单的,我写的可能不是太好,建议方法二中有不明白的去官方解答看看。
加油加油加油加油加油加油!!!!
加油哦!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值