|
| 1 | +/** |
| 2 | + * [124] Binary Tree Maximum Path Sum |
| 3 | + * |
| 4 | + * Given a non-empty binary tree, find the maximum path sum. |
| 5 | + * |
| 6 | + * For this problem, a path is defined as any sequence of nodes from some starting node to any node in the tree along the parent-child connections. The path must contain at least one node and does not need to go through the root. |
| 7 | + * |
| 8 | + * Example 1: |
| 9 | + * |
| 10 | + * |
| 11 | + * Input: [1,2,3] |
| 12 | + * |
| 13 | + * 1 |
| 14 | + * / \ |
| 15 | + * 2 3 |
| 16 | + * |
| 17 | + * Output: 6 |
| 18 | + * |
| 19 | + * |
| 20 | + * Example 2: |
| 21 | + * |
| 22 | + * |
| 23 | + * Input: [-10,9,20,null,null,15,7] |
| 24 | + * |
| 25 | + * -10 |
| 26 | + * / \ |
| 27 | + * 9 20 |
| 28 | + * / \ |
| 29 | + * 15 7 |
| 30 | + * |
| 31 | + * Output: 42 |
| 32 | + * |
| 33 | + * |
| 34 | + */ |
| 35 | +pub struct Solution {} |
| 36 | +use super::util::tree::{TreeNode, to_tree}; |
| 37 | + |
| 38 | +// submission codes start here |
| 39 | + |
| 40 | +/* |
| 41 | + 典型的动态规划, 我们求以 node_i 为 root 的最大和, 可以下推到求 root 的左右子树, 这里要注意, 路径是不能分叉的, 因此 |
| 42 | + 我们记 f[node] 为以 node 为根的最大和, 记 g[node] 为 node 为根, *最多连通一侧子树*的最大和 |
| 43 | +
|
| 44 | + 我们在递推时要用 g[node], f[node] 在递推过程中每次计算一下用于更新 max 即可 |
| 45 | +
|
| 46 | + g[node_i] = node_i.val + max(g[node_i.left], g[node_i.right], 0) |
| 47 | + f[node_i] = node_i.val + max(g[node_i.left], 0) + max(g[node_i.right], 0) |
| 48 | +
|
| 49 | + 显然, g[None] = 0 (None 即空子树), 最终计算到 g[root] 中止, f 的最大值会在计算过程中出现(注意 f[root] 不一定是最大值) |
| 50 | +
|
| 51 | + 每个 node 最大和只依赖与其左右子树的最大和, 因此 Top-down 需要 O(N) 的空间 |
| 52 | + Bottom-up 只需要 O(1) 空间 (做后序遍历从叶节点向上递推即可) |
| 53 | + */ |
| 54 | +use std::rc::Rc; |
| 55 | +use std::cell::RefCell; |
| 56 | +impl Solution { |
| 57 | + pub fn max_path_sum(root: Option<Rc<RefCell<TreeNode>>>) -> i32 { |
| 58 | + let mut max = i32::min_value(); |
| 59 | + Solution::postorder(root.as_ref(), &mut max); |
| 60 | + max |
| 61 | + } |
| 62 | + |
| 63 | + fn postorder(root: Option<&Rc<RefCell<TreeNode>>>, max: &mut i32) -> i32 { |
| 64 | + if let Some(node) = root { |
| 65 | + let left = Solution::postorder(node.borrow().left.as_ref(), max); |
| 66 | + let right = Solution::postorder(node.borrow().right.as_ref(), max); |
| 67 | + *max = i32::max(node.borrow().val + i32::max(left, 0) + i32::max(right, 0), *max); |
| 68 | + node.borrow().val + i32::max(i32::max(left, right), 0) |
| 69 | + } else { |
| 70 | + 0 |
| 71 | + } |
| 72 | + } |
| 73 | +} |
| 74 | + |
| 75 | +// submission codes end |
| 76 | + |
| 77 | +#[cfg(test)] |
| 78 | +mod tests { |
| 79 | + use super::*; |
| 80 | + |
| 81 | + #[test] |
| 82 | + fn test_124() { |
| 83 | + assert_eq!(Solution::max_path_sum(tree![1,2,3]), 6); |
| 84 | + assert_eq!(Solution::max_path_sum(tree![-10,9,20,null,null,15,7]), 42); |
| 85 | + assert_eq!(Solution::max_path_sum(tree![5,4,8,11,null,13,4,7,2,null,null,null,1]), 48); |
| 86 | + assert_eq!(Solution::max_path_sum(tree![-3]), -3); |
| 87 | + } |
| 88 | +} |
0 commit comments