[LeetCode] 124. 二叉树中的最大路径和(深度优先遍历)

124. 二叉树中的最大路径和

给定一个非空二叉树,返回其最大路径和。

本题中,路径被定义为一条从树中任意节点出发,达到任意节点的序列。该路径至少包含一个节点,且不一定经过根节点。
在这里插入图片描述
解题思路: 本题题意是求解树中最大路径序列和(这里路径的定义是从一个节点到达另一个节点,不一定经过根节点),那么一条路径的形成是由节点、向左子树延展的路径、向右子树延展的路径组成,(这里延展的路径与我们常规理解的路径定义相同但不一定取整个直达叶子节点的全路径),那么想要题面定义的路径最长,只需左子树延展的路径和右子树延展路径均最长,就能使包含此节点的路径序列和最大,因此遍历过程中存在大量重复计算为降低时间复杂度,可以用记忆数组保存结果.

class Solution {
public:
    int maxPathVal(TreeNode* node) {
        if (mp.count(node)) return mp[node];
        if (!node) return 0;
        int res = node->val;
        int mx = max(maxPathVal(node->left), maxPathVal(node->right));
        res += max(0, mx);
        return mp[node] = res;
    }
    int helper(TreeNode* node) {
        if (!node) return 0;
        int mxleft = maxPathVal(node->left);
        int mxright = maxPathVal(node->right);
        return node->val + max(0, mxleft) + max(0, mxright);
    }
    void dfs(TreeNode* root) {
        if (!root) return;
        maxres = max(maxres, helper(root));
        dfs(root->left);
        dfs(root->right);
    }
    int maxPathSum(TreeNode* root) {
        dfs(root);
        return maxres;
    }
private:
    unordered_map<TreeNode*, int> mp;
    int maxres = INT_MIN;
};

看群友的解法,似乎增加一个函数解题,我新增了三个函数,在解此题时,我一直在想着如何将题目分解到我们平常已做过的题的解法,树的最大路径的题我们之前做过类似的有树的最长路径(无权值问题,根节点直达叶子节点问题),那么联想到此题,最自然的想法是,题目定义的路径一定是穿过某个节点的(简称节点A),那这条路径有三个延展方向,即左子树、右子树、父节点,而向上延展的父节点其实跟父节点向左右延展至子树的情况重复了,所以我们只需要考虑向左右子树延展的路径(定义1),那么我们可以先写一个求这个路径(定义1)最大值的函数,然后求题面路径时,只需要分别求左子树路径和右子树路径分别取正数然后与节点值加和即可。模块化编程,减少思维压力。

最后研究了一下群友的解题思路,发现我的解题思路和群友的解题是差不多的,群友的helper函数,本质上是求以访问节点为起点,向左子树和右子树延展能取得的最大路径,然后以根节点启动遍历,相当于对所有节点都遍历了一次,遍历的过程中记录题面定义的最大路径。定义一个求事件A的函数,在函数中也做一些其他的事,比如事件B,此类做法在算法题中可以这么干,但是在工程代码中,我觉得还是一个函数表达一件事,最好不要串扰,不然函数的行为很难追踪。

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

——————————
注:(定义1)粗体路径是指以该节点为起点且向左或者右子树延展的路径,与书本上路径定义大致相同,区别是不一定要到叶子节点。

写在后面

此题的收获是,解决一些陌生题时要学会将问题分解,分解到我们之前已经做过的题上,对应二叉树路径和的玩法,归结起来就一下几点:

  1. 求根节点到叶子节点的路径和(这是这类题的基础)
  2. 根节点到中间节点路径、中间节点到叶子节点路径,本质还是要点1
  3. 中间节点到中间节点,此题如果不转换,很容易误以为用图的遍历解决,但是树没有前向指针,这样会把问题弄复杂了。对于此问题要分解到要点1和要点2解题。本题属于这类问题。
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值