[LeetCode] 865. Smallest Subtree with all the Deepest Nodes 包含最深結點的最小子樹



Given a binary tree rooted at root, the depth of each node is the shortest distance to the root.html

A node is deepest if it has the largest depth possible among any node in the entire tree.node

The subtree of a node is that node, plus the set of all descendants of that node.git

Return the node with the largest depth such that it contains all the deepest nodes in its subtree.github

Example 1:函數

Input: [3,5,1,6,2,0,8,null,null,7,4]
Output: [2,7,4]
Explanation:

We return the node with value 2, colored in yellow in the diagram.
The nodes colored in blue are the deepest nodes of the tree.
The input "[3, 5, 1, 6, 2, 0, 8, null, null, 7, 4]" is a serialization of the given tree.
The output "[2, 7, 4]" is a serialization of the subtree rooted at the node with value 2.
Both the input and output have TreeNode type.

Note:code

  • The number of nodes in the tree will be between 1 and 500.
  • The values of each node are unique.



這道題給了咱們一棵二叉樹,讓咱們找包含全部最深結點的最小子樹,就是返回這棵最小子樹的根結點。題目中給了一個例子,由於有圖,因此能夠很直接的看出來最深的結點是7和4,那麼包含這兩個結點的最小子樹的根結點是2,返回便可。其實最深的結點不必定只有兩個,可能有不少個,好比對於一棵徹底二叉樹,即把例子圖中的結點7和4去掉後,此時最深的結點就有四個,分別是6,2,0,8,都包含這些結點的子樹就是原樹自己了,要返回根結點。htm

經過上述分析,能夠發現,子樹的最大深度很重要,對於一棵徹底二叉樹來講,根結點的左右子樹的最大深度必定是相同的,此時直接返回根結點便可。若左右子樹的最大深度不一樣,則最深結點必定位於深度大的子樹中,能夠對其調用遞歸函數。因此只須要寫一個計算最大深度的遞歸函數,來計算左右子樹的最大深度差,再根據這個差值來決定對誰調用當前的遞歸函數,兩個遞歸函數相互纏繞,畫面美極了,參見代碼以下:blog



解法一:遞歸

class Solution {
public:
    TreeNode* subtreeWithAllDeepest(TreeNode* root) {
        int diff = depth(root->left) - depth(root->right);
        return (diff == 0) ? root : subtreeWithAllDeepest(diff > 0 ? root->left : root->right);
    }
    int depth(TreeNode* node) {
        return !node ? 0 : max(depth(node->left), depth(node->right)) + 1;
    }
};



上面的解法其實並不高效,由於對於每一個結點,都要統計其左右子樹的最大深度,有大量的重複計算存在,咱們來嘗試提升時間複雜度,就不可避免的要犧牲一些空間。遞歸函數須要返回一個 pair,由每一個結點的最大深度,以及包含最深結點的最小子樹組成。因此在原函數中,對根結點調用遞歸函數,並取返回的 pair 中的第二項。ci

在遞歸函數中,首先判斷結點是否存在,爲空的話直接返回一個 {0, NULL} 對兒。不然分別對左右子結點調用遞歸函數,將各自的返回的 pair 存入 left 和 right 中,而後先分別在 left 和 right 中取出左右子樹的最大深度 d1 和 d2,以後就要創建返回值的 pair,第一項爲當前結點的最大深度,由左右子樹中的最大深度加1組成,而包含最深結點的最小子樹由 d1 和 d2 值的大小決定,若 d1>d2,則爲 left.second,不然爲 right.second,這樣咱們就把本來的兩個遞歸,揉合到了一個遞歸函數中,大大提升了運行效率,參見代碼以下:



解法二:

class Solution {
public:
    TreeNode* subtreeWithAllDeepest(TreeNode* root) {
        return helper(root).second;
    }
    pair<int, TreeNode*> helper(TreeNode* node) {
        if (!node) return {0, NULL};
        auto left = helper(node->left), right = helper(node->right);
        int d1 = left.first, d2 = right.first;
        return {max(d1, d2) + 1, (d1 == d2) ? node : (d1 > d2 ? left.second : right.second)};
    }
};



Github 同步地址:

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



參考資料:

https://leetcode.com/problems/smallest-subtree-with-all-the-deepest-nodes/

https://leetcode.com/problems/smallest-subtree-with-all-the-deepest-nodes/discuss/146808/One-pass

https://leetcode.com/problems/smallest-subtree-with-all-the-deepest-nodes/discuss/146786/Simple-recursive-Java-Solution

https://leetcode.com/problems/smallest-subtree-with-all-the-deepest-nodes/discuss/146842/Short-and-concise-C%2B%2B-solution-using-DFS-3~5-lines



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

相關文章
相關標籤/搜索