跳到主要内容

LeetCode 337. 打家劫舍 III

本节目标

后序同时返回选当前节点和不选当前节点的最大金额。

题意与约束

二叉树相邻父子不能同时选择,返回可选节点值之和的最大值。

第一反应与重复子问题

选择一个节点会限制子节点,不选择则子节点可各自最优;每棵子树都需要同样的两种答案。

状态定义与转移推导

后序返回 (take, skip)take = val + left.skip + right.skipskip = max(left) + max(right)

正确性依据

父节点的唯一约束只涉及直接子节点,给定父节点选或不选后左右子树独立,二元状态穷尽所有合法情况。

样例执行过程

示例树根为 3 时,选择根会搭配两个子树的 skip,最终取到 7

代码实现

C++17
#include <algorithm>
#include <functional>
#include <utility>
using namespace std;

class Solution {
public:
int rob(TreeNode* root) {
function<pair<int, int>(TreeNode*)> dfs = [&](TreeNode* node) -> pair<int, int> {
if (!node) {
return {0, 0};
}
auto left = dfs(node->left);
auto right = dfs(node->right);
return {
node->val + left.second + right.second,
max(left.first, left.second) + max(right.first, right.second),
};
};
auto result = dfs(root);
return max(result.first, result.second);
}
};

复杂度分析

每个节点计算一次,时间 O(n)。C++ 实现使用递归,调用栈为 O(h);Python 实现使用显式栈并保存每个节点的状态,额外空间为 O(n)

边界与易错点

空树返回零;TreeNode 由平台提供,源码不应重复定义,状态也不能残留到下一次调用。

模式迁移

树上的相邻互斥可用选/不选状态;若约束变为覆盖关系,状态数会增加。回到树形动态规划