daily leetcode - binary-tree-maximum-path-sum - !

题目地址

https://leetcode.com/problems/binary-tree-maximum-path-sum/

题目描述

Given a non-empty binary tree, find the maximum path sum.

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.

Example 1:

Input: [1,2,3]

       1
      / \
     2   3

Output: 6

Example 2:

Input: [-10,9,20,null,null,15,7]

   -10
   / \
  9  20
    /  \
   15   7

Output: 42

思路

这道求二叉树的最大路径和是一道蛮有难度的题,难就难在起始位置和结束位置可以为任意位置,博主当然是又不会了,于是上网看看大神们的解法,像这种类似树的遍历的题,一般来说都需要用 DFS 来求解,先来看一个简单的例子:

    4
   / \
  11 13
 / \
7   2

由于这是一个很简单的例子,很容易就能找到最长路径为 7->11->4->13,那么怎么用递归来找出正确的路径和呢?根据以往的经验,树的递归解法一般都是递归到叶节点,然后开始边处理边回溯到根节点。这里就假设此时已经递归到结点7了,其没有左右子节点,如果以结点7为根结点的子树最大路径和就是7。然后回溯到结点 11,如果以结点 11 为根结点的子树,最大路径和为 7+11+2=20。但是当回溯到结点4的时候,对于结点 11 来说,就不能同时取两条路径了,只能取左路径,或者是右路径,所以当根结点是4的时候,那么结点 11 只能取其左子结点7,因为7大于2。所以,对于每个结点来说,要知道经过其左子结点的 path 之和大还是经过右子节点的 path 之和大。递归函数返回值就可以定义为以当前结点为根结点,到叶节点的最大路径之和,然后全局路径最大值放在参数中,用结果 res 来表示。

在递归函数中,如果当前结点不存在,直接返回0。否则就分别对其左右子节点调用递归函数,由于路径和有可能为负数,这里当然不希望加上负的路径和,所以和0相比,取较大的那个,就是要么不加,加就要加正数。然后来更新全局最大值结果 res,就是以左子结点为终点的最大 path 之和加上以右子结点为终点的最大 path 之和,还要加上当前结点值,这样就组成了一个条完整的路径。而返回值是取 left 和 right 中的较大值加上当前结点值,因为返回值的定义是以当前结点为终点的 path 之和,所以只能取 left 和 right 中较大的那个值,而不是两个都要,参见代码如下:

class Solution {
public:
    int maxPathSum(TreeNode* root) {
        int res = INT_MIN;
        helper(root, res);
        return res;
    }
    int helper(TreeNode* node, int& res) {
        if (!node) return 0;
        int left = max(helper(node->left, res), 0);
        int right = max(helper(node->right, res), 0);
        res = max(res, left + right + node->val);
        return max(left, right) + node->val;
    }
};

讨论:这道题有一个很好的 Follow up,就是返回这个最大路径,那么就复杂很多,因为这样递归函数就不能返回路径和了,而是返回该路径上所有的结点组成的数组,递归的参数还要保留最大路径之和,同时还需要最大路径结点的数组,然后对左右子节点调用递归函数后得到的是数组,要统计出数组之和,并且跟0比较,如果小于0,和清零,数组清空。然后就是更新最大路径之和跟数组啦,还要拼出来返回值数组,代码长了很多,有兴趣的童鞋可以在评论区贴上你的代码~

思路2

这道题目的path让我误解了,然后浪费了很多时间来解这道题
我觉得leetcode给的demo太少了,不足以让我理解path的概念
因此我这里自己画了一个图,来补充一下,帮助大家理解path的概念,不要像我一样理解错啦。

首先是官网给的两个例子:

124.binary-tree-maximum-path-sum

接着是我自己画的一个例子:

124.binary-tree-maximum-path-sum

大家可以结合上面的demo来继续理解一下path, 除非你理解了path,否则不要往下看。

树的题目,基本都是考察递归思想的。因此我们需要思考如何去定义我们的递归函数,
在这里我定义了一个递归函数,它的功能是,返回以当前节点为根节点的MathPath
但是有两个条件:

  1. 第一是跟节点必须选择
  2. 第二是左右子树只能选择一个

为什么要有这两个条件?

我的想法是原问题可以转化为:

以每一个节点为根节点,我们分别求出max path,最后计算最大值,因此第一个条件需要满足.

对于第二个,由于递归函数子节点的返回值会被父节点使用,因此我们如果两个孩子都选择了
就不符合max path的定义了,这也是我没有理解题意,绕了很大弯子的原因。

因此我的做法就是不断调用递归函数,然后在调用过程中不断计算和更新max,最后在主函数中将max返回即可。

关键点解析

  • 递归
  • 理解题目中的path定义

代码



/*
 * @lc app=leetcode id=124 lang=javascript
 *
 * [124] Binary Tree Maximum Path Sum
 */
/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
function helper(node, payload) {
  if (node === null) return 0;

  const l = helper(node.left, payload);
  const r = helper(node.right, payload);

  payload.max = Math.max(
    node.val + Math.max(0, l) + Math.max(0, r),
    payload.max
  );

  return node.val + Math.max(l, r, 0);
}
/**
 * @param {TreeNode} root
 * @return {number}
 */
var maxPathSum = function(root) {
  if (root === null) return 0;
  const payload = {
    max: root.val
  };
  helper(root, payload);
  return payload.max;
};

本文参考自:
https://github.com/grandyang/leetcode/ &
https://github.com/azl397985856/leetcode


标题: daily leetcode - binary-tree-maximum-path-sum - !
文章作者: lonuslan
文章链接: https://www.lonuslan.com/articles/2020/07/07/1594091562030.html
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Hi I'm LonusLan
    评论
    0 评论
avatar

取消