力扣(LeetCode)124

題目地址:
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的題目,如果不寫前面的鋪墊直接給出答案,多半是看不懂的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章