[Leetcode] Several important recursive problems of binary tree are summarized with detailed problem-solving ideas

One, leetcode236

Title description

Given a binary tree, find the nearest common ancestor of two specified nodes in the tree.
The definition of the nearest common ancestor in Baidu Encyclopedia is: "For the two nodes p and q of the rooted tree T, the nearest common ancestor is expressed as a node x, so that x is the ancestor of p and q and the depth of x is as large as possible (A node can also be its own ancestor)."
For example, given the following binary tree: root = [3,5,1,6,2,0,8,null,null,7,4]
Example 1:
Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
Output: 3
Explanation: The nearest common ancestor of node 5 and node 1 is node 3 .
Example 2:
Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
Output: 5
Explanation: The nearest of node 5 and node 4 The common ancestor is node 5. Because by definition the nearest common ancestor node can be the node itself.

Passed code

(1) The best code available online

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
    
    
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    
    
        if(root==NULL||root==p||root==q)//递归的终止条件
        return root;
        TreeNode*left=lowestCommonAncestor(root->left,p,q);
        TreeNode*right=lowestCommonAncestor(root->right,p,q);//每层递归要做的事情
        if(left==NULL&&right==NULL)//每层递归的返回,三种情况分别讨论
        return NULL;
        else if(left!=NULL&&right!=NULL)
        return root;
        else
        return left==NULL?right:left;
    }
};

(2) The code I wrote myself

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
    
    
public:
    vector<TreeNode*>route1;
    vector<TreeNode*>route2;
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    
    
        vector<TreeNode*>route;
        int minSize;
        TreeNode *node;
        int i;
        route.push_back(root);
        dfs(root,route,p,q);
        minSize=min(route1.size(),route2.size());
        for(i=0;i<minSize;i++)
        {
    
    
            if(route1[i]!=route2[i])
            break;
        }
        node=route1[i-1];
        return node;
    }
    void dfs(TreeNode* node,vector<TreeNode*>&route,TreeNode* p, TreeNode* q)
    {
    
    
        if(node==NULL)
        return ;
        if(route[route.size()-1]==p)
        route1=route;
        if(route[route.size()-1]==q)
        route2=route;
        if(node->left)
        {
    
    
            route.push_back(node->left);
            dfs(node->left,route,p,q);
            route.pop_back();
        }
        if(node->right)
        {
    
    
            route.push_back(node->right);
            dfs(node->right,route,p,q);
            route.pop_back();
        }
    }
};


Problem solving ideas

When I wrote this topic myself, my idea was to get the path from the root node to the two nodes p and q through the dfs function, save the two paths, and then find that the first of the two paths is different The last identical node before the node. This idea is easy to come up with. But after writing the code, I found that the amount of code is still not small. So I searched for other people's code and found that it is also recursive. The best code on the Internet is very simple, that is, the first code above.
In fact, the idea is to search for p and q nodes on the left and right of the root of the current layer each time you reach a certain level of recursion. If both left and right are NULL, it means p and q are not on the left and right sides of the current root, so they return NULL; if the left and right sides are not NULL, it means that the p and q nodes must be distributed on the left and right sides of the root respectively, and return to root at this time. Root is the nearest common ancestor of the two specified nodes that we think in the title; if one of the left and right is not NULL, it means that there is a node on one side, and there is no node on the other side, and it must return at this time The node searched on the side that is not NULL. The third case is a bit difficult to understand. I think the third case actually contains two possible situations, one is that the p and q nodes are all located on one side of root, and the first node found at this time The point is the nearest common ancestor of the two specified nodes considered in the title, so it can be returned directly. Another situation is that the p or q node is located on one side of the root. At this time, we can return to this node first, and then combine the results to get the nearest common ancestor of the last two specified nodes.
I feel that there are three most important points of recursion. One is to know the termination condition of the recursion, the other is to know what each layer of recursion does, and the other is to know what each layer of recursion returns. This problem is similar to the problem-solving process of balanced binary tree and calculating the depth of the binary tree. Each level of recursion must get a certain value of left and right on the left and right sides of the current node, and then make a judgment and return what the current layer wants to return.
I haven't mastered the recursive problem of binary trees very well, so I need to practice more later.

Two, leetcode226

Title description

Flip a binary tree.

Example:

Input:
4
/
27
/ \ /
1369

Output:
4
/
72
/ \ /
9631

Passed code

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
    
    
public:
    TreeNode* invertTree(TreeNode* root) {
    
    
        if(root==NULL)
        return NULL;
        else if(root->left==NULL&&root->right==NULL)
        return root;
        TreeNode*p;
        TreeNode*q;
        p=invertTree(root->right);
        q=invertTree(root->left);
        root->left=p;//这里不能直接写成root->left=invertTree(root->right);
        root->right=q;//这里不能直接写成root->right=invertTree(root->left);
        return root;
    }
};

Problem solving ideas

It is another recursive problem of binary trees. Because of the experience of the first topic above, I began to look for the conditions for recursive termination, what to do in each layer and the results returned by each layer. The termination condition of this problem is when the root node is NULL on both sides, that is, when the root node is a leaf node, because at this time, the current node root can be returned directly without any operation (because there is no left and right , There is no need to flip the child nodes). Each layer is to exchange the left and right subtrees of the current root node, which is the flip in the title. And each layer returns to the root node after flipping. The above three steps have been found, and the problem will be solved.
There is a point that needs attention, I marked it in the code, because I didn't notice it at first.

Three, leetcode543

Title description

Given a binary tree, you need to calculate its diameter and length. The diameter length of a binary tree is the maximum of the path lengths of any two nodes. This path may or may not pass through the root node.
Example:
Given a binary tree

      1
     / \
    2   3
   / \     
  4   5    

Return 3, its length is the path [4,2,1,3] or [5,2,1,3].
Note: The length of the path between two nodes is expressed by the number of edges between them.

Passed code

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
    
    
public:
    int ans=0;
    int diameterOfBinaryTree(TreeNode* root) {
    
    
        dep(root);
        return ans;
    }
    int dep(TreeNode*root)
    {
    
    
        if(root==NULL)
        return 0;
        int left=dep(root->left);
        int right=dep(root->right);
        if((left+right)>ans)
        ans=left+right;
        return max(left,right)+1;
    }
};

Problem solving ideas

This topic is very similar to the two above. Each layer is recursively solved for a left and a right, which is actually the depth of the left and right sides. Of course, the depth here is from bottom to top. After all, the diameter of the topic is calculated. This is how it is defined. Then each layer returns to the depth corresponding to the root node. And calculate a diameter in each layer, if it is larger than the previously saved, replace ans.
So too, just find the three steps to do. And I found that what these topics do in each recursive layer is to calculate left and right separately, then judge and return. The ideas are similar.

Four, link

Summary of Recursive Algorithms
This blog post mentions the three steps above, which is very good. Save the blog post here, you can read it later

Guess you like

Origin blog.csdn.net/qq_38391210/article/details/108310649