大家好,我是挨打的阿木木,爱好算法的前端摸鱼老。最近会频繁给大家分享我刷算法题过程中的思路和心得。如果你也是想提高逼格的摸鱼老,欢迎关注我,一起学习。
题目
124. 二叉树中的最大路径和
路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。
路径和 是路径中各节点值的总和。
给你一个二叉树的根节点 root ,返回其 最大路径和 。
示例 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
提示:
- 树中节点数目范围是
[1, 3 * 104] -1000 <= Node.val <= 1000
思路
求最大路径和: 可以转换成递归的问题, 首先最大路径和要么存在根节点,要么存在根节点的左子树,也就是左节点,要么存在左子树,也就是右节点,只有这三种情况,我们层层递归转换下去即可。但是由于要求路径和,所以我们得先求出每个节点的最长路径,用map也就是前缀和来记录,然后才能通过第二次遍历去递归的找到最大路径和。
- 先找到各个节点的最大路径和,取左右节点和的最大值加上当前节点的值;
- 再次遍历树,对比每个节点的三种情况:取左边,取右边,或者取中间;
- 形成一个递归问题,递归的转移方程是把求解当前节点的最大值分成了三个部分做比较。
实现
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {number}
*/
var maxPathSum = function(root) {
if (!root) return 0;
let map = getPathMap(root);
function getPathSum(node) {
if (!node) return 0;
let leftValue = Math.max((map.get(node.left) || 0), 0);
let rightValue = Math.max((map.get(node.right) || 0), 0);
// 当前节点的最大值,等于左右两个节点的最大值和加当前值
let cur = node.val + leftValue + rightValue;
let compareList = [ cur ];
node.left && compareList.push(getPathSum(node.left));
node.right && compareList.push(getPathSum(node.right));
return Math.max(...compareList);
}
return getPathSum(root, map);
};
// 找到每个节点的路径前缀和
function getPathMap(root) {
let map = new Map();
// 找到每个节点的最大单边路径,
const getMaxPath = (node) => {
if (!node) return 0;
const maxSubValue = Math.max(getMaxPath(node.left), getMaxPath(node.right));
const maxValue = maxSubValue > 0 ? node.val + maxSubValue : node.val;
map.set(node, maxValue);
return maxValue;
}
getMaxPath(root);
return map;
}
优化
- 我们发现自上而下的递归,需要用
map保存一遍值,同时走两轮递归才能找到相应的结果; - 但是自下而上的递归则不用,可以获取最长路径的同时直接在外部记录最大值即可。
优化代码
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {number}
*/
var maxPathSum = function(root) {
if (!root) return 0;
let maxValue = Number.MIN_SAFE_INTEGER;
// 找到每个节点的最大单边路径
const getMaxPath = (node) => {
if (!node) return 0;
// 后序遍历,先找子节点
// 如果节点路径是负的我们就不加,当作没有这个节点
const leftValue = Math.max(getMaxPath(node.left), 0);
const rightValue = Math.max(getMaxPath(node.right), 0);
// 把总路径和最大值记录下来
maxValue = Math.max(maxValue, node.val + leftValue + rightValue);
return Math.max(leftValue, rightValue) + node.val;
}
getMaxPath(root);
return maxValue;
};
看懂了的小伙伴可以点个关注、咱们下道题目见。如无意外以后文章都会以这种形式,有好的建议欢迎评论区留言。