LeetCode 865. Smallest Subtree with all the Deepest Nodes [tree, DFS, BFS, hash table] 1534

This article belongs to one of the series of articles "Conquering LeetCode". This series officially started on 2021/08/12. Since some questions on LeetCode are locked, this series will continue at least until all unlocked questions are cleared; since LeetCode is still creating new questions, the end date of this series may be forever. In this series of problem-solving articles, I will not only explain a variety of problem-solving ideas and their optimization, but also use a variety of programming languages ​​to solve the problems. When it comes to general solution methods, I will also summarize the corresponding algorithm templates.

In order to facilitate running, debugging and sharing code files on PC, I also established a related warehouse: https://github.com/memcpy0/LeetCode-Conquest . In this warehouse, you can not only see the link to the original LeetCode question, solution code, link to the solution article, summary of similar questions, summary of common solutions, etc., but also important information such as the frequency of original questions and related companies. If you have other preferred solutions, you can share them with others.

Since the content of this series of articles may be updated and changed at any time, you are welcome to follow and save the article Table of Contents of the Conquering LeetCode series of articles as a reminder.

Given a rootbinary tree with root , the depth of each node is the shortest distance from that node to the root .

Returns the smallest subtree containing all deepest nodes in the original tree .

A node is the deepest if it has the greatest depth among any nodes in the entire tree .

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

Example 1:

输入:root = [3,5,1,6,2,0,8,null,null,7,4]
输出:[2,7,4]
解释:
我们返回值为 2 的节点,在图中用黄色标记。
在图中用蓝色标记的是树的最深的节点。
注意,节点 532 包含树中最深的节点,但节点 2 的子树最小,因此我们返回它。

Example 2:

输入:root = [1]
输出:[1]
解释:根节点是树中最深的节点。

Example 3:

输入:root = [0,1,3,null,2]
输出:[2]
解释:树中最深的节点为 2 ,有效子树为节点 210 的子树,但节点 2 的子树最小。

hint:

  • The number of nodes in the tree is in [1, 500]the range.
  • 0 <= Node.val <= 500
  • The value of each node is unique .

Note: This question is duplicated with Leetcode 1123: https://leetcode-cn.com/problems/lowest-common-ancestor-of-deepest-leaves


Solution 1 Recursion


Looking at the picture above (example 1), the nodes of this tree are 3, 5, 2 3,5,23,5,2 are all deepest leaf nodes7, 4 7,47,common ancestor of 4 , but only node2 22 is the most recent common ancestor.

If the node we are looking for is only in the left subtree, then the most recent common ancestor must also be only in the left subtree. For this question, if the maximum depth of the left subtree is greater than that of the right subtree, then the deepest leaf node is only in the left subtree, so the most recent common ancestor is only in the left subtree . On the other hand, if the maximum depth of the right subtree is greater than the left subtree, then the deepest leaf node is only in the right subtree, so the most recent common ancestor is only in the right subtree.

What if the maximum depth of the left and right subtrees is the same? Does the current node have to be the most recent common ancestor? uncertain. For example, node 1 1The deepest leaf nodes of the left and right subtrees of 1 are 0, 8 0,80,The depth of 8 is2 22 , but the depth is notthe global maximum depth, so node1 11 is not the answer.

Based on the above discussion, the correct approach is as follows:

  • Recurse this binary tree while maintaining the global maximum depth maxDepth \textit{maxDepth}maxDepth
  • Pass depth depth when " passing "d e pt h , used to representthe depth of the current node.
  • When " returning ", upload the depth of the deepest leaf node of the current subtree .
  • Let the depth of the deepest leaf node of the left subtree be leftMaxDepth \textit{leftMaxDepth}leftMaxDepth , the depth of the deepest leaf node of the right subtree isrightMaxDepth \textit{rightMaxDepth}rightMaxDepth 。如果 leftMaxDepth = rightMaxDepth = maxDepth \textit{leftMaxDepth}=\textit{rightMaxDepth}=\textit{maxDepth} leftMaxDepth=rightMaxDepth=maxDepth , then update the answer to the current node. Note that this does not mean that we have found the answer. If deeper leaf nodes are found later, the answer will be updated.
class Solution {
    
    
public:
    TreeNode *subtreeWithAllDeepest(TreeNode *root) {
    
    
        TreeNode *ans = nullptr;
        int max_depth = -1; // 全局最大深度
        function<int(TreeNode*, int)> dfs = [&](TreeNode *node, int depth) {
    
    
            if (node == nullptr) {
    
    
                max_depth = max(max_depth, depth); // 维护全局最大深度
                return depth;
            }
            int left_max_depth = dfs(node->left, depth + 1); // 获取左子树最深叶节点的深度
            int right_max_depth = dfs(node->right, depth + 1); // 获取右子树最深叶节点的深度
            if (left_max_depth == right_max_depth && left_max_depth == max_depth)
                ans = node;
            return max(left_max_depth, right_max_depth); // 当前子树最深叶节点的深度
        };
        dfs(root, 0);
        return ans;
    }
};

Complexity analysis:

  • Time complexity: O ( n ) \mathcal{O}(n)O ( n ) . Each node will be visited exactly once.
  • Space complexity: O ( n ) \mathcal{O}(n)O ( n ) . In the worst case, the binary tree is a chain, and recursion requires O(n)\mathcal{O}(n)O(n) stack space.

Solution 2 Bottom-up

We can also use global variables instead of treating each subtree as a "sub-problem" . That is, for each subtree, we need to know:

  • The depth of the deepest leaf node of this subtree. This refers to the depth of the leaf within this subtree, not the depth from the perspective of the entire binary tree. Equivalent to the height of this subtree .
  • The nearest common ancestor of the deepest leaf node of this subtree lca \textit{lca}lca

Classification discussion:

  • Let the root node of the subtree be node nodenode n o d e node The height of the left subtree of n o d e is leftHeight \textit{leftHeight}leftHeight n o d e node The height of the right subtree of n o d e is rightHeight \textit{rightHeight}rightHeight
  • 如果 l e f t H e i g h t > r i g h t H e i g h t leftHeight>rightHeight leftHeight>r i g h t He i g h t , then the height of the subtree isleftHeight + 1 \textit{leftHeight} + 1leftHeight+1 lca \textit{lca} lca is the lca of the left subtree\textit{lca}lca
  • 如果 leftHeight < rightHeight \textit{leftHeight} < \textit{rightHeight} leftHeight<rightHeight , then the height of the subtree isright H eight + 1 rightHeight+1rightHeight+1 l c a lca l c a is lca lcaof the right subtreelca
  • if leftHeight = rightHeight \textit{leftHeight} = \textit{rightHeight}leftHeight=rightHeight , then the height of the subtree isleftHeight + 1 \textit{leftHeight} + 1leftHeight+1 l c a lca l c a isnode noden o d e . Proof by contradiction: iflca lcal c a is in the left subtree, thenlca lcal c a is not the ancestor of the deepest leaf node of the right subtree, which is wrong; iflca lcal c a is in the right subtree, thenlca lcal c a is not the ancestor of the deepest leaf node of the left subtree, which is also wrong; iflca lcal c a innode noden o d e , it does not meet the "recent" requirement. Solca lcal c a can only benode nodenode
class Solution {
    
    
    pair<int, TreeNode*> dfs(TreeNode *node) {
    
    
        if (node == nullptr)
            return {
    
    0, nullptr};
        auto [left_height, left_lca] = dfs(node->left);
        auto [right_height, right_lca] = dfs(node->right);
        if (left_height > right_height) // 左子树更高
            return {
    
    left_height + 1, left_lca};
        if (left_height < right_height) // 右子树更高
            return {
    
    right_height + 1, right_lca};
        return {
    
    left_height + 1, node}; // 一样高
    }

public:
    TreeNode *subtreeWithAllDeepest(TreeNode *root) {
    
    
        return dfs(root).second;
    }
};

Complexity analysis:

  • Time complexity: O ( n ) \mathcal{O}(n)O ( n ) . Each node will be visited exactly once.
  • Space complexity: O ( n ) \mathcal{O}(n)O ( n ) . In the worst case, the binary tree is a chain, and recursion requiresO ( n ) \mathcal{O}(n)O ( n ) stack space.

A more concise way of writing it is:

class Solution {
    
    
public:
    int depth[1010];
    TreeNode* subtreeWithAllDeepest(TreeNode* root) {
    
    
        if (root == nullptr) return nullptr;
        TreeNode* left = root->left, *right = root->right;
        TreeNode* lcaLeft = subtreeWithAllDeepest(root->left), *lcaRight = subtreeWithAllDeepest(root->right);
        int dl = left ? depth[left->val] : 0, dr = right ? depth[right->val] : 0;
        depth[root->val] = max(dl, dr) + 1;
        if (dl > dr) return lcaLeft;
        if (dr > dl) return lcaRight;
        return root;
    }
};

Guess you like

Origin blog.csdn.net/myRealization/article/details/132748063