题目地址:
https://leetcode-cn.com/probl…
题目描述:
给定一个非空二叉树,返回其最大路径和。本题中,路径被定义为一条从树中任意节点出发,达到任意节点的序列。该路径至少包含一个节点,且不一定经过根节点。示例 1:
输入: [1,2,3]
1
/ \
2 3
输出: 6
示例 2:
输入: [-10,9,20,null,null,15,7]
-10
/ \
9 20
/ \
15 7
输出: 42
解答:
这一题,看上去,根本不可能做出来!为什么呢?因为这里的 路径和 很特别,它可以是从任意点到任意点的路径,搜索我都搜索不出来,按照定义路径可以是从一个叶子到另一个叶子,比如这样:
-10
/ \
9 20
/ \
15 7
15->20->7, 这条路径,怎么搜索?搜索的代码都写不出来!!!
那么只能放弃了。。。
我认为直接求路径和这题是无解的,写不出代码。而这一题我是求别的东西,顺带求出了答案。
但是想一下下面的几个 简单 问题,这个问题就能做出来了!
(如果跳过这几个简单问题直接看答案,除非你天赋异禀,否则能看懂那你这思维也是没谁了)
二叉树的深度怎么求?
int depth(TreeNode root)
{if(root == null)return 0;
return 1+Math.max(depth(root.left),depth(root.right));
}
二叉树的深度等于,max(左子树的深度, 右子树的深度)+1。
假设二叉树的 val 字段为 int 类型。
基于求深度的思想,进阶一下求 根节点到 叶节点的 最大路径和:
int maxSum(TreeNode root)
{if(root == null)return 0;
return root.val + Math.max(maxSum(root.left),maxSum(root.right));
}
根到叶的最大路径和等于 max(左子树根到叶最大路径和,右子树根到叶最大路径和)+root.val。
现在求,根节点到某一子节点,使得该路径和最大,该子节点可以不是叶子节点,给出最大路径长度。
how?
这个和上面那俩其实是一个原理,给这个函数起个名字叫做 ” 根向下最大延申 ”
那么算法是:
int temp =max(左子树根向下最大延申,右子树根向下最大延申)。
若 temp > 0, 则根向下最大延申 =root.val+temp, 否则根向下最大延申 =root.val
代码为:
int dfs(TreeNode root)
{if(root == null)return 0;
int left = dfs(root.left);
int right = dfs(root.right);
int temp = Math.max(left,right);
if(temp > 0)
temp += root.val;
else
temp = root.val;
return temp;
}
求出上面这个有什么用!!!???用处实在是 太大了 啊啊啊啊啊!!!!!
求出了上面这个,这个问题就基本可解了!!!
为什么呢?
我们这么想,给我任意一个树的节点 root,现在给这个 ” 根向下最大延申 ” 函数起个英文名叫做 dfs。那么 经过 这个节点的最大路径和只可能是下面几种情况:
1、
root.val
该节点本身值。
2、
dfs(root.left)+root.val,该节点本身值 + 左子树向下最大延申。
此时 dfs(root.left) > 0 && dfs(root.right) <= 0。
3、
dfs(root.right)+root.val,该节点本身值 + 右子树向下最大延申。
此时 dfs(root.left) <= 0 && dfs(root.right) > 0。
4、dfs(root.left)+dfs(root.right)+root.val
该节点本身值 + 左右子树向下最大延申。
此时 dfs(root.left) > 0 && dfs(root.right) > 0。
上面四种情况 包含了 经过这个节点的最大路径和的 所有可能 。
虽然 不能 求出 任意点 到任意点 的路径和,但是已经可以得到该题的解了!!!
(读者可以想想为什么不求出任意点到任意点的路径和也能求出答案)
因此,对于任意一个节点 root,求出 经过该节点的最大路径和 ,然后和全局答案
进行比较,更新全局答案为最大值,就能够求出这一题的答案!!!
java ac 代码:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) {val = x;}
* }
*/
class Solution {public int maxPathSum(TreeNode root) {if(root == null)return 0;
dfs(root);
return ans;
}
int ans = Integer.MIN_VALUE;
// 求该点能向下延申的最大值
int dfs(TreeNode root)
{if(root == null)return 0;
int left = dfs(root.left);
int right = dfs(root.right);
int temp = Math.max(left,right);
if(temp > 0)
temp += root.val;
else
temp = root.val;
int val = root.val;
if(left >= 0)val += left;
if(right >= 0)val += right;
ans = Math.max(ans,val);
return temp;
}
}
Amazing!!!
代码如此 优美 ,每个节点只被访问一次,使得 时间效率 应该也是 最优的 ,并且还能求出答案,真是 Unbelievable!
这题还能这么解!!!这题让求最大路径和,实际上是求根节点向下最大延申,而路径和只是顺带着求出来的。
为什么不直接给出答案?这是一道 hard 的题目,如果不写前面的铺垫直接给出答案,多半是看不懂的。