[LeetCode] 508. Most Frequent Subtree Sum 出現頻率最高的子樹和


 

Given the root of a tree, you are asked to find the most frequent subtree sum. The subtree sum of a node is defined as the sum of all the node values formed by the subtree rooted at that node (including the node itself). So what is the most frequent subtree sum value? If there is a tie, return all the values with the highest frequency in any order.

Examples 1
Input:

  5
 /  \
2   -3

return [2, -3, 4], since all the values happen only once, return all of them in any order.

 

Examples 2
Input:

  5
 /  \
2   -5

return [2], since 2 happens twice, however -5 only occur once.

 

Note: You may assume the sum of values in any subtree is in the range of 32-bit signed integer.

 

這道題給了我們一個二叉樹,讓我們求出現頻率最高的子樹之和,求樹的結點和並不是很難,就是遍歷所有結點累加起來即可。那么這道題的暴力解法就是遍歷每個結點,對於每個結點都看作子樹的根結點,然后再遍歷子樹所有結點求和,這樣也許可以通過 OJ,但是絕對不是最好的方法。我們想下子樹有何特點,必須是要有葉結點,單獨的一個葉結點也可以當作是子樹,那么子樹是從下往上構建的,這種特點很適合使用后序遍歷,我們使用一個 HashMap 來建立子樹和跟其出現頻率的映射,用一個變量 cnt 來記錄當前最多的次數,遞歸函數返回的是以當前結點為根結點的子樹結點值之和,然后在遞歸函數中,我們先對當前結點的左右子結點調用遞歸函數,然后加上當前結點值,然后更新對應的 HashMap 中的值,然后看此時 HashMap 中的值是否大於等於 cnt,大於的話首先要清空 res,等於的話不用,然后將 sum 值加入結果 res 中即可,參見代碼如下:

 

解法一:

class Solution {
public:
    vector<int> findFrequentTreeSum(TreeNode* root) {
        vector<int> res;
        unordered_map<int, int> m;
        int cnt = 0;
        postorder(root, m, cnt, res);
        return res;
    }
    int postorder(TreeNode* node, unordered_map<int, int>& m, int& cnt, vector<int>& res) {
        if (!node) return 0;
        int left = postorder(node->left, m, cnt, res);
        int right = postorder(node->right, m, cnt, res);
        int sum = left + right + node->val;
        ++m[sum];
        if (m[sum] >= cnt) {
            if (m[sum] > cnt) res.clear();
            res.push_back(sum);
            cnt = m[sum];
        }
        return sum;
    }
};

 

下面這種解法跟上面的基本一樣,就是沒有在遞歸函數中更新結果 res,更是利用 cnt,最后再更新 res,這樣做能略微高效一些,參見代碼如下:

 

解法二:

class Solution {
public:
    vector<int> findFrequentTreeSum(TreeNode* root) {
        vector<int> res;
        unordered_map<int, int> m;
        int cnt = 0;
        postorder(root, m, cnt);
        for (auto a : m) {
            if (a.second == cnt) res.push_back(a.first);
        }
        return res;
    }
    int postorder(TreeNode* node, unordered_map<int, int>& m, int& cnt) {
        if (!node) return 0;
        int left = postorder(node->left, m, cnt);
        int right = postorder(node->right, m, cnt);
        int sum = left + right + node->val;
        cnt = max(cnt, ++m[sum]);
        return sum;
    }
};

 

開始我還在想能不能利用后序遍歷的迭代形式來解,后來想了半天發現不太容易實現,因為博主無法想出有效的機制來保存左子樹結點之和,而計算完對應的右子樹結點之和后要用到對應的左子樹結點之和,才能繼續往上算。可能博主不夠 smart,有大神如果知道如何用迭代的形式來解,請一定要留言告知博主啊,多謝啦~

 

Github 同步地址:

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

 

類似題目:

Subtree of Another Tree

 

參考資料:

https://leetcode.com/problems/most-frequent-subtree-sum/

https://leetcode.com/problems/most-frequent-subtree-sum/discuss/98675/JavaC%2B%2BPython-DFS-Find-Subtree-Sum

https://leetcode.com/problems/most-frequent-subtree-sum/discuss/98664/Verbose-Java-solution-postOrder-traverse-HashMap-(18ms)

 

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


免責聲明!

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



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