[LeetCode] 437. Path Sum III 二叉樹的路徑和之三


 

You are given a binary tree in which each node contains an integer value.

Find the number of paths that sum to a given value.

The path does not need to start or end at the root or a leaf, but it must go downwards (traveling only from parent nodes to child nodes).

The tree has no more than 1,000 nodes and the values are in the range -1,000,000 to 1,000,000.

Example:

root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8

      10
     /  \
    5   -3
   / \    \
  3   2   11
 / \   \
3  -2   1

Return 3. The paths that sum to 8 are:

1.  5 -> 3
2.  5 -> 2 -> 1
3. -3 -> 11

 

這道題讓我們求二叉樹的路徑的和等於一個給定值,說明了這條路徑不必要從根節點開始,可以是中間的任意一段,而且二叉樹的節點值也是有正有負。那么可以用遞歸來做,相當於先序遍歷二叉樹,對於每一個節點都有記錄了一條從根節點到當前節點到路徑,同時用一個變量 curSum 記錄路徑節點總和,然后看 curSum 和 sum 是否相等,相等的話結果 res 加1,不等的話繼續查看子路徑和有沒有滿足題意的,做法就是每次去掉一個節點,看路徑和是否等於給定值,注意最后必須留一個節點,不能全去掉了,因為如果全去掉了,路徑之和為0,而如果給定值剛好為0的話就會有問題,整體來說不算一道很難的題,參見代碼如下:

 

解法一:

class Solution {
public:
    int pathSum(TreeNode* root, int sum) {
        int res = 0;
        vector<TreeNode*> out;
        helper(root, sum, 0, out, res);
        return res;
    }
    void helper(TreeNode* node, int sum, int curSum, vector<TreeNode*>& out, int& res) {
        if (!node) return;
        curSum += node->val;
        out.push_back(node);
        if (curSum == sum) ++res;
        int t = curSum;
        for (int i = 0; i < out.size() - 1; ++i) {
            t -= out[i]->val;
            if (t == sum) ++res;
        }
        helper(node->left, sum, curSum, out, res);
        helper(node->right, sum, curSum, out, res);
        out.pop_back();
    }
};

 

我們還可以對上面的方法進行一些優化,來去掉一些不必要的計算,可以用 HashMap 來建立路徑之和跟其個數之間的映射,即路徑之和為 curSum 的個數為 m[curSum],這里需要將 m[0] 初始化為1,后面會講解原因。在遞歸函數中,首先判空,若為空,直接返回0。然后就是 curSum 加上當前結點值。由於此時 curSum 可能已經大於了目標值 sum,所以用 curSum 減去 sum,並去 HashMap 中查找這個差值的映射值,若映射值大於0的化,說明存在結束點為當前結點且和為 sum 的路徑,這就相當於累加和數組快速求某個區域和的原理。當 curSum 等於 sum 的時候,表明從根結點到當前結點正好是一條符合要求的路徑,此時 res 應該大於0,這就是為啥要初始化 m[0] 為1的原因,舉個例子來說吧,看下面這棵樹:

    1
   /
  2
 /
1

假設 sum=3,當遍歷根結點1時,curSum 為1,那么 curSum-sum=-2,映射值為0,然后建立映射 m[1]=1。此時遍歷結點2,curSum 為3,那么 curSum-sum=0,由於 m[0] 初始化為1,所以 res=1,這是 make sense 的,因為存在和為3的路徑。此時再遍歷到第二個結點1,curSum 為4,那么 curSum-sum=1,由於之前建立了 m[1]=1 的映射,所以當前的 res 也為1,因為存在以第二個結點1為結尾且和為3的路徑,那么遞歸返回到結點2時候,此時的 res 累加到了2,再返回根結點1時,res 就是2,最終就返回了2,那么可以看出遞歸函數的意義,某個結點的遞歸函數的返回值就是該結點上方或下方所有和為 sum 的路徑總個數,參見代碼如下:

 

解法二:

class Solution {
public:
    int pathSum(TreeNode* root, int sum) {
        unordered_map<int, int> m;
        m[0] = 1;
        return helper(root, sum, 0, m);
    }
    int helper(TreeNode* node, int sum, int curSum, unordered_map<int, int>& m) {
        if (!node) return 0;
        curSum += node->val;
        int res = m[curSum - sum];
        ++m[curSum];
        res += helper(node->left, sum, curSum, m) + helper(node->right, sum, curSum, m);
        --m[curSum];
        return res;
    }
};

 

下面這種方法非常的簡潔,用了兩個遞歸函數,其中的一個 sumUp 遞歸函數是以當前結點為起點,和為 sum 的路徑個數,采用了前序遍歷,對於每個遍歷到的節點進行處理,維護一個變量 pre 來記錄之前路徑之和,然后 cur 為 pre 加上當前節點值,如果 cur 等於 sum,那么返回結果時要加1,然后對當前節點的左右子節點調用遞歸函數求解,這是 sumUp 遞歸函數。而在 pathSum 函數中,我們對當前結點調用 sumUp 函數,加上對左右子結點調用 pathSum 遞歸函數,三者的返回值相加就是所求,參見代碼如下:

 

解法三:

class Solution {
public:
    int pathSum(TreeNode* root, int sum) {
        if (!root) return 0;
        return sumUp(root, 0, sum) + pathSum(root->left, sum) + pathSum(root->right, sum);
    }
    int sumUp(TreeNode* node, int pre, int& sum) {
        if (!node) return 0;
        int cur = pre + node->val;
        return (cur == sum) + sumUp(node->left, cur, sum) + sumUp(node->right, cur, sum);
    }
};

 

Github 同步地址:

https://github.com/grandyang/leetcode/issues/437

 

類似題目:

Binary Tree Maximum Path Sum

Path Sum II

Path Sum

Minimum Path Sum

Path Sum IV

Longest Univalue Path 

 

參考資料:

https://leetcode.com/problems/path-sum-iii/

https://leetcode.com/problems/path-sum-iii/discuss/91889/Simple-Java-DFS

https://leetcode.com/problems/path-sum-iii/discuss/91878/17-ms-O(n)-java-Prefix-sum-method

 

LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM