- 题目描述
路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。路径和 是路径中各节点值的总和。给你一个二叉树的根节点 root ,返回其 最大路径和 。
提示:
- 树中节点数目范围是 [1, 3 * 104]
- -1000 <= Node.val <= 1000
来源:LeetCode
- 示例
- 示例 1:
输入:root = [1,2,3]
输出:6
解释:最优路径是 2 -> 1 -> 3 ,路径和为 2 + 1 + 3 = 6 - 示例 2:
输入:root = [-10,9,20,null,null,15,7]
输出:42
解释:最优路径是 15 -> 20 -> 7 ,路径和为 15 + 20 + 7 = 42
-示例3:
输入:root = [1,-2,-3,1,3,-2, null, -1]
输出:3
- 思路分析
这道题看起来不算难,但是妹想到我被困住了这么久。
- 最初的错误想法:先中序遍历,放入链表中,然后再用动态规划求子序列的最大和就可以了。我觉得自己聪明绝顶,但是示例3无法通过,我才发现我真傻。
- 然后我想到了递归。要求最大路径,假定一个根节点root,那么围绕这个节点的路径,就有如下几种情况:
1 root.left + root + root.right
2 root.right + root (+ root.parent)
3 root.left + root (+ root.parent)
4 root (+ root.parent)
root.parent用括号括起来是因为在root节点时,并没有真的计算root.parent,只是用于表示这个路径的走向是向上走的。 - 因此与root节点有关的最大路径就是这四种路径的最大值,而为了继续向上走,那么只有2,3和4三种情况可以,因此返回2,3,4的最大值就可以。
- 我在这里的全局最大和某个节点的最大卡了很久,因为递归返回的结果是某个结点的最大,但是需要的是全局最大。我想过用全局变量,但是又觉得好像不太严谨,就一直卡着。结果最后还是用了全局变量。
- JAVA实现
class Solution {
int max = -1000; //因为一个节点的最小值是-1000
public int maxPathSum(TreeNode root) {
cal(root);
return max;
}
public int cal(TreeNode root) {
int left = 0, right = 0;
int leftIn = 0, rightIn = 0, allIn = 0;
int pathSum;
if(root.left != null) left = cal(root.left);
if(root.right != null) right = cal(root.right);
leftIn = root.val + left; //3
rightIn = root.val + right; //2
allIn = root.val + right + left; //1
pathSum = Math.max(Math.max(leftIn, rightIn), Math.max(root.val, allIn));
max = Math.max(max, pathSum);
return Math.max(root.val, Math.max(leftIn, rightIn)); //被困在了这个返回值和全局最大之间之间
}
}