题目:题目链接
思路:题目就是说选了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]);//选最大的
}
};
官方解答还是比较简单的,我写的可能不是太好,建议方法二中有不明白的去官方解答看看。
加油加油加油加油加油加油!!!!
加油哦!!