记录 1 道算法题
二叉树中的最大路径和
在路径上节点不能重复,可以不经过根节点。
一般是
a
b
c
d
or
b // b 不是根节点,a才是
c d
e
f
就是如果子节点的累加和比根节点一直以来的累加还要大的时候,就是不经过根节点获得最大路径和。
如果从递归的视角来看,并不是从根节点开始,累加,然后传下去。而是从最底下的叶子节点开始向上累加,和二叉树的高度类似了。
最底下叶子节点,然后上一层,左节点加当前节点和右节点加当前节点相比,选出最大的作为路径向上返回。
但是因为有可以不经过根节点的情况,就是截断这棵树了。
这种不经过根节点的情况的判断条件是需要外部存储一个变量的。因为递归只会返回左边或右边的最大累加。
当 左中右 加起来比一路累加的还要大时就更新这个外部变量。但是递归只会返回左边或右边路径的累加,而且并不保存到外部存储的变量里,而是保存左中右的和,为什么可以是左中右的值呢。是因为递归一路返回到根节点时,最后的情况也是根节点的 左中右,所以只比较左中右没有什么问题。另外记的是最大的路径和,所以如果后面递归返回的左右路径没有大于当前的最大值,那么可以判断为最大路径是不经过根节点。
执行是思路是递归左右节点,如果是叶子节点,他的左右子节点返回 0, 不要影响判断。然后返回了左路径和右路径的累加。然后比较 左中右,如果左中右比一路累加起来的大,就把最大值更新为左中右,意味着最大路径和不经过根节点。然后递归函数的返回值是左路径或由陆军中的最大值与当前节点值的和,意思就是把当前节点加入到路径,然后返回作为上一层的左路径或右路径。
function maxPathSum(root) {
// 这个最大值默认是根节点
let count = root.val
function f(root) {
if (!root) return 0
// 左路径和右路径,
// 如果小于0则说明最大路径和是不包括这些子节点,
// 所以排除,也是一种局部最优的体现
const a = Math.max(f(root.left), 0)
const b = Math.max(f(root.right), 0)
// 更新最大和,是继续左右路径还是直接到此为止
count = Math.max(count, a + b + root.val)
// 返回左路径或右路径
return Math.max(a, b) + root.val
}
f(root)
return count
}