2022-08-08 16:17阅读: 26评论: 0推荐: 0

力扣-337-打家劫舍Ⅲ

直达链接

打家劫舍的区别在于,打家劫舍原题是数组,这里是二叉树
而且这里只能由根节点开始
回顾一下之前的思路,看有什么异同、是否还适用

访问任意节点,当前节点可获得最大价值为:

  1. 不要当前节点值,那么收益便是:截至上一个节点的值(上一个节点?!这里只能知道子节点不能知道父节点)
  2. 要当前值,那么获得的价值便是:当前价值+截至上上个节点获取的价值(上个都没法知道,怎么知道上上个?!)
  3. 这里是树形路径而不是单一线性路径,而且入口是根节点,无法“自底向下”

重新想一想
自顶向下

  1. 要当前节点价值,那么最大价值为:当前节点价值+截至左右子节点的所有子节点所能获取的最大价值
  2. 不要当前节点,可获得最大价值为:截至左右子节点所能获得的最大价值

感觉很像是“有状态”的搜索,自顶向下规划,递归……

官方题解

这边用到了两个数据结构来动态规划

class Solution {
public:
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) {}
};
unordered_map <TreeNode*, int> f, g;
void dfs(TreeNode* node) {
if (!node) return;
dfs(node->left);
dfs(node->right);
f[node] = node->val + g[node->left] + g[node->right];
g[node] = max(f[node->left], g[node->right]) + max(f[node->right], g[node->left]);
}
int rob(TreeNode* root) {
dfs(root);
return max(f[root], g[root]);
}
};

这确实是没见过的新东西——二叉树的动态规划

再看看“小小的空间优化“:

struct SubtreeStatus {
int selected;
int notSelected;
};
class Solution {
public:
SubtreeStatus dfs(TreeNode* node) {
if (!node) return{0,0};
auto l = dfs(node->left);
auto r = dfs(node->right);
int selected = node->val + l.notSelected + r.notSelected;
int notSlected = max(l.selected, l.notSelected) + max(r.selected, r.notSelected);
return {selected,notSelected};
}
int rob(TreeNode* root) {
auto rootStatus = dfs(root);
return max(rootStatus.notSelected,rootStatus.selected);
}
};

很多时候动态规划并不需要知道过往所有的值,只需要前一步的值就够了

本文作者:YaosGHC

本文链接:https://www.cnblogs.com/yaocy/p/16527828.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   YaosGHC  阅读(26)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起