求二叉樹(shù)最大路徑和(Binary Tree Maximum Path Sum)

leetcode題目鏈接

題目描述

Given a binary tree, find the maximum path sum.
給出一棵二叉樹(shù),計(jì)算其最大路徑和。
The path may start and end at any node in the tree.
路徑的起止結(jié)點(diǎn)必須位于樹(shù)內(nèi)。
For example:
例如:
Given the below binary tree,
給出如下二叉樹(shù):

   1
  / \
 2   3

Return 6.
返回6(sum path 2-1-3)

解題思路

假設(shè),我們正在處理的子樹(shù)的根結(jié)點(diǎn)root一定位于這個(gè)path內(nèi),我們計(jì)算當(dāng)path一定經(jīng)過(guò)了root時(shí)的最大路徑和max(root)。
那么max(root)該如何計(jì)算呢?
我們假設(shè)我們已經(jīng)求除了當(dāng)path一定經(jīng)過(guò)root->left時(shí)的最大路徑和max(root->left),也求除了當(dāng)path一定經(jīng)過(guò)root->right時(shí)的最大路徑和max(root->right),這時(shí)候,如果max(root->left)>0,那么對(duì)于root而言,將root->left和root連接起來(lái)的path的和一定比root自己構(gòu)成的path的和要大;
同理,如果max(root->right)>0,那么對(duì)于root而言,將root->left和root連接起來(lái)的path的和一定比root自己構(gòu)成的path的和要大。
然而對(duì)于一條路徑來(lái)說(shuō),
root要么跟root->left連接在一起,
要么跟root->right連接在一起.

因此我們需要對(duì)
root->data+max(root->left)
root->data
root->data +max(root->right)
求出其中的最大值來(lái)作為max(root)的值。

有了如上的步驟之后,我們到底該如何確定二叉樹(shù)的最大路徑和呢?
實(shí)際上,我們上述過(guò)程是求得了以某一個(gè)結(jié)點(diǎn)為根的子樹(shù)的最大路徑和,其中路徑的起點(diǎn)為根,終點(diǎn)為子樹(shù)中的某一結(jié)點(diǎn),我們注意到這個(gè)過(guò)程中,我們每次都只是從根的左右子結(jié)點(diǎn)中選擇其中的一個(gè)來(lái)連接到path中,實(shí)際上,一個(gè)path是有可能既連接root->left,又連接root->right的,但是這種情況至多會(huì)出現(xiàn)在其中一個(gè)結(jié)點(diǎn)x上,否則就會(huì)出現(xiàn)路徑的分叉了。
因此,我們?cè)谇蟮膍ax(root->left)、max(root->right)之后,嘗試將root作為我們上面提到的x點(diǎn),然后來(lái)計(jì)算由max(root->left)、max(root->right)、root->val可能構(gòu)成的最大和tmp,然后判定tmp和當(dāng)前緩存好的max(最大路徑和),并更新max值即可。
最后,這個(gè)max就是我們要求的最大路徑和。

算法

1.如果root為NULL,返回0

2.遞歸調(diào)用1-5,求得maxSum(root->left)和maxSum(root->right)
3.maxSum(root) = max(root->data, root->data + maxSum(root->left), root->data + maxSum(root->right))

4.判定root->val 、 maxSum(root->left)、maxSum(root->right)三者可能構(gòu)成的最大和(必須包含root->data),是否大于目前緩存的最大路徑和tmp,如果是則更新tmp

5.返回maxSum(root)的值

6.遞歸調(diào)用結(jié)束后,tmp的值就是最大路徑和

代碼實(shí)現(xiàn)

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MaxLen 15

//定義節(jié)點(diǎn)
typedef struct node
{
    struct node *lchild;
    struct node *rchild;
    int data;
} BitNode, *BiTree;
//*BiTree的意思是給 struct node*起了個(gè)別名,叫BiTree,故BiTree為指向節(jié)點(diǎn)的指針。


void printArray(int arr[],int length)
{
    for (int i = 0; i<length; i++) {
        printf(" %d",arr[i]);
    }
    printf("\n");
}

BiTree creatBTree(int data[],int index,int n)
{
    BiTree pNode = NULL;
    
    if(index < n && (data[index]!=0))  //數(shù)組中-1 表示該節(jié)點(diǎn)為空
    {
        pNode = (BitNode *)malloc(sizeof(BitNode));
        if(pNode == NULL)
            return NULL;
        pNode->data = data[index];
        pNode->lchild = creatBTree(data, 2 * index + 1, n);  //將二叉樹(shù)按照層序遍歷, 依次標(biāo)序號(hào), 從0開(kāi)始
        pNode->rchild = creatBTree(data, 2 * index + 2, n);
    }
    
    return pNode;
}

//先序遍歷
void PreOrder(BiTree p)
{
    if(p != NULL)
    {
        printf(" %d",p->data);      //輸出該結(jié)點(diǎn)
        PreOrder(p->lchild);  //遍歷左子樹(shù)
        PreOrder(p->rchild); //遍歷右子樹(shù)
    }
    else
    {
        printf(" #");
    }
}

/* 求兩個(gè)數(shù)中較大的數(shù)字 */
int max(int arg1, int arg2)
{ return arg1 > arg2 ? arg1 : arg2; }

/* 求3個(gè)數(shù)中較大的數(shù)字 */
int maxThree(int arg1, int arg2, int arg3)
{ return max(arg1, max(arg2, arg3)); }


/**
 * 計(jì)算二叉樹(shù)子樹(shù)的最大路徑和以及整棵二叉樹(shù)的最大路徑和
 * 子樹(shù)路徑必須以根結(jié)點(diǎn)開(kāi)始,以樹(shù)中某一結(jié)點(diǎn)結(jié)束
 * 二叉樹(shù)的最大路徑和的路徑,不必以根結(jié)點(diǎn)為開(kāi)始結(jié)點(diǎn)
 * @param root 二叉樹(shù)根結(jié)點(diǎn)
 * @param tmpMax 暫存整棵二叉樹(shù)的最路徑和的變量的地址
 * @return 子樹(shù)的最大路徑和
 */
int maxChildPathSum(BiTree root, int *tmpMax)
{
    
    if (root == NULL)
    {
        //printf("\n");
        return 0;
    }
    else
    {
       // printf("%d ",root->data);
    }
  
    /* 計(jì)算左右子樹(shù)的最大路徑和 */
    int leftMax = maxChildPathSum(root->lchild, tmpMax);
    int rightMax = maxChildPathSum(root->rchild, tmpMax);
    
    /* 嘗試更新整棵二叉樹(shù)的最大路徑和 */
    int tmp = root->data;
   
    if (leftMax > 0)
    {
        tmp += leftMax;
        
    }
    if (rightMax > 0)
    {
        tmp += rightMax;
        
    }
    
  
    
    if (tmp > *tmpMax)
    {
        *tmpMax = tmp;
        
    }
    
    /* 計(jì)算并返回子樹(shù)的最大路徑和 */
    int maxRoot = maxThree(root->data,root->data+leftMax, root->data+rightMax);
    
    return maxRoot;
}

/**
 * 計(jì)算二叉樹(shù)的最大路徑和
 * @param  root 二叉樹(shù)根結(jié)點(diǎn)
 * @return 最大路徑和
 */
int maxPathSum(BiTree root)
{
    if (root == NULL) return 0;
    
    int tmpMax = root->data;
    
    maxChildPathSum(root, &tmpMax);
    
    return tmpMax;
}

int main(int argc, const char * argv[]) {
    
    int arr[MaxLen] ;
    srand( (unsigned)time( NULL ) );
    for (int i = 0; i<MaxLen; i++)
    {
        arr[i] = rand()%30+1-15;
    }
    printf("原始數(shù)組:\n");
    printArray(arr, MaxLen);
    BiTree tree = creatBTree(arr, 0, MaxLen);

    
    printf("先序遍歷:\n");
    PreOrder(tree);
    printf("\n");
    
    
    printf("\n");
    printf("最大路徑和=%d\n",maxPathSum(tree));
    printf("\n");
    
   // printf("先序遍歷:\n");
    //PreOrder(tree);
   // printf("\n");
    
    return 0;
}

運(yùn)行結(jié)果

可視化二叉樹(shù)

原始數(shù)組:
 7 -9 -10 -8 6 1 -12 5 10 4 4 -6 11 -4 -6
先序遍歷:
 7 -9 -8 5 # # 10 # # 6 4 # # 4 # # -10 1 -6 # # 11 # # -12 -4 # # -6 # #

最大路徑和=14

Program ended with exit code: 0
最大路徑和.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容