Popular Binary Tree Interview Questions

606. Create String from Binary Tree - LeetCode

Given the root node of the binary tree root, please use preorder traversal to convert the binary tree into a string composed of brackets and integers, and return the constructed string.

Empty nodes are represented by a pair of empty brackets "()". After conversion, all empty brackets that do not affect the one-to-one mapping between the string and the original binary tree need to be omitted.

Example 1:

输入:root = [1,2,3,4]
输出:"1(2(4))(3)"
解释:初步转化后得到 "1(2(4)())(3()())" ,但省略所有不必要的空括号对后,字符串应该是"1(2(4))(3)" 。

Example 2:

输入:root = [1,2,3,null,4]
输出:"1(2()(4))(3)"
解释:和第一个示例类似,但是无法省略第一个空括号对,否则会破坏输入与输出一一映射的关系。

Analysis: Input 1, 2, 3, 4 in Example 1, and then output 1, 2, 4, 3. Then it is easy to see that it is a pre-order traversal of a binary tree. The pre-order traversal order of the binary tree is about middle , which solves the order problem, and the next step is the problem of parentheses.

There are four situations

1: only the left son

2: Only the right son

3: No left and right sons

4: There are left and right sons

Then it can be obtained after simplification 1(2(4))(3).

class Solution {
public:

    void Pre(TreeNode* t,string& str)
    {
        if(t==nullptr) return;//为空直接返回,包括了没有左右儿子的情况,直接不打印

        str+=to_string(t->val);
        if(t->left)//左子树
        {
            str+="(";
            Pre(t->left,str);
            str+=")";
        }
        
        if(t->right)//右子树
        {
            str+="(";
            Pre(t->right,str);
            str+=")";
        }

    }

    string tree2str(TreeNode* root) {
        string res="";
        Pre(root,res);
        return res;
    }
};

But it seems to be different from the result, a parenthesis is missing, let's simulate it.

When recursing to node 2, 2->left is empty, and it returns directly. After returning, nothing is printed here, so the result is wrong, so the first if condition can be changed if(t->left||t->right).

class Solution {
public:

    void Pre(TreeNode* t,string& str)
    {
        if(t==nullptr) return;//为空直接返回,包括了没有左右儿子的情况,直接不打印

        str+=to_string(t->val);
        if(t->left||t->right)//左子树/左子树和右子树都存在
        {
            str+="(";
            Pre(t->left,str);
            str+=")";
        }
        
        if(t->right)//右子树
        {
            str+="(";
            Pre(t->right,str);
            str+=")";
        }

    }

    string tree2str(TreeNode* root) {
        string res="";
        Pre(root,res);
        return res;
    }
};

102. Level order traversal of binary tree - LeetCode

Given the root node of your binary tree , return a level-order traversalroot of its node values . (ie layer by layer, visit all nodes from left to right).

Example 1:

输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]

Example 2:

输入:root = [1]
输出:[[1]]

Example 3:

输入:root = []
输出:[]

Layer order traversal, BFS, old routine problem, use a queue to simulate the traversal process.

For example, 3 enters the team at the beginning, gets node 3, and 3 leaves the team, then adds 3 and 3's left and right child nodes to the answer, adds 9 and 20 to the queue, then gets node 9, leaves the team, and 9 has no left and right child nodes, so continue to get node 20, 20 and then leave the team, and add the left and right child nodes of 20 and 20 to the answer.

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>>res;
        if(!root) return res;
        
        queue<TreeNode*>q;
        q.push(root);
        while(!q.empty())
        {
            vector<int>tmp;
            int sz=q.size();//记录当前层数有多少节点,就要循环取多少次,一定要提前记录,不然q.size()会改变。
            for(int i=0;i<sz;i++)
            {
                auto node=q.front();//取队头
                tmp.push_back(node->val);//入暂存的答案数组
                q.pop();//出队
                if(node->left)
                {
                    q.push(node->left);
                }
                if(node->right)
                {
                    q.push(node->right);
                }
            }
            res.push_back(tmp);
        }
        return res;
    }
};

107. Level order traversal of binary tree II - LeetCode

Given the root node of your binary tree , return the bottom-up order traversal ofroot its node values . (That is, traverse from left to right layer by layer from the layer where the leaf node is located to the layer where the root node is located)

Example 1:

输入:root = [3,9,20,null,null,15,7]
输出:[[15,7],[9,20],[3]]

Example 2:

输入:root = [1]
输出:[[1]]

Example 3:

输入:root = []
输出:[]

There is nothing to say about this question, just reverse the result on the basis of the previous question.

class Solution {
public:
    vector<vector<int>> levelOrderBottom(TreeNode* root) {
        queue<TreeNode*>q;
        if(root!=nullptr)
        {
            q.push(root);
        }
        vector<vector<int>>res;
        while(!q.empty())
        {
            int size=q.size();
            vector<int> vec;
            for(int i=0;i<size;i++)
            {
                auto node=q.front();
                q.pop();
                vec.push_back(node->val);
                if(node->left) q.push(node->left);
                if(node->right) q.push(node->right);
            }
            res.push_back(vec);
        } 
        reverse(res.begin(),res.end());
        return res;
    }
};

236. The nearest common ancestor of the binary tree - LeetCode

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 two nodes p and q of a rooted tree T, the nearest common ancestor is expressed as a node x, satisfying 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) . "

Example 1:

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点 5 和节点 1 的最近公共祖先是节点 3 。

Example 2:

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出:5
解释:节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。

Example 3:

输入:root = [1,2], p = 1, q = 2
输出:1

There are three situations in this question.

1: all in the left subtree

2: All in the right subtree

3: one on the left, one on the right

First look at the situation where one is on the left and the other is on the right, which is best judged. The nearest common ancestor in this case is the root node.

Then in the left subtree: we only need to search the left subtree for the first node that is found por qis the nearest common ancestor.

The right subtree is the same as the left subtree.

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root==nullptr||root==p||root==q) return root;
        TreeNode* left=lowestCommonAncestor(root->left,p,q);
        TreeNode* right=lowestCommonAncestor(root->right,p,q);
        if(left==nullptr) return right;
        else if(right==nullptr) return left;
        return root;
    }
};

105. Construct Binary Tree from Preorder and Inorder Traversal Sequence - LeetCode

Given two integer arrays preorderand inorder, where is the preorder traversalpreorder of a binary tree and is the inorder traversal of the same tree , construct a binary tree and return its root node.inorder

Example 1:

输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出: [3,9,20,null,null,15,7]

Example 2:

输入: preorder = [-1], inorder = [-1]
输出: [-1]

Preorder traversal order: middle left

Inorder traversal order: left, middle, right

It can be seen that the first node of the pre-order traversal is the root node, and if the root node is found, the number of left and right subtrees can be determined by in-order traversal

For example, in the figure below, the first node of the preorder traversal is 3, then the root node is 3, then go to the inorder traversal to find 3, divide the left and right subtrees with 3 as the boundary, 9 is the left side, 20, 15, and 7 are the right side.

class Solution {
public:

    unordered_map<int,int>pos;

    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        for(int i=0;i<inorder.size();i++)
        {
            pos[inorder[i]]=i;
        }
        return build(preorder,inorder,0,preorder.size()-1,0,inorder.size()-1);
    }

    TreeNode* build(vector<int>& preorder,vector<int>& inorder,int pl,int pr,int il,int ir)
    {
        if(pl>pr) return nullptr;
        TreeNode* root=new TreeNode(preorder[pl]);//前序遍历的第一个元素是根节点
        int pos1=pos[root->val];
        root->left=build(preorder,inorder,pl+1,pl+1+pos1-1-il,il,pos1-1);
        root->right=build(preorder,inorder,pl+1+pos1-il,pr,pos1+1,ir);
        return root;
    }
};

106. Construct Binary Tree from Inorder and Postorder Traversal Sequences - LeetCode

Given two integer arrays inorderand postorder, where inorderis the inorder traversal of a binary tree and postorderthe postorder traversal of the same tree, please construct and return this binary tree .

Example 1:

输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]
输出:[3,9,20,null,null,15,7]

Example 2:

输入:inorder = [-1], postorder = [-1]
输出:[-1]

The idea is almost the same as the previous question, and the analysis is as shown in the figure above

class Solution {
public:

    unordered_map<int,int>pos;
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        for(int i=0;i<inorder.size();i++)
        {
            pos[inorder[i]]=i;//记录中序遍历的每个点的位置
        }
        return build(inorder,postorder,0,inorder.size()-1,0,postorder.size()-1);
    }

    TreeNode* build(vector<int>& inorder,vector<int>&postorder,int il,int ir,int pl,int pr)
    {
        if(pl>pr)return nullptr;
        TreeNode* root=new TreeNode(postorder[pr]);
        int k=pos[root->val];
        root->left=build(inorder,postorder,il,k-1,pl,pl+(k-1-il));
        root->right=build(inorder,postorder,k+1,ir,pl+k-il,pr-1);
        return root;
    }
};

144. Preorder Traversal of Binary Tree - LeetCode

Given the root node of your binary tree , return a preorderroot traversal of its node values .

Example 1:

输入:root = [1,null,2,3]
输出:[1,2,3]

Example 2:

输入:root = []
输出:[]

Example 3:

输入:root = [1]
输出:[1]

Example 4:

输入:root = [1,2]
输出:[1,2]

Example 5:

输入:root = [1,null,2]
输出:[1,2]

The preorder traversal recursive version is simple:

class Solution {
public:
    vector<int>res;
    vector<int> preorderTraversal(TreeNode* root) {
        pre(root);
        return res;
    }

    void pre(TreeNode* root)
    {
        if(root==nullptr)return;
        res.push_back(root->val);
        pre(root->left);
        pre(root->right);
    }
};

Non-recursive version:

The preorder traversal is: middle, left, and right, so first go to the left node of the node, and then go to the right, and add the value of the current node to the answer while walking.

Here you can use a stack to simulate the process, if it is such a tree

If there is 1 2 4 6no right node, the elements in the stack will be popped until node 2. If there is a right node in 2, 5 will be added to the stack and the answer. If 5 has no right node, it will continue to pop out of the stack until 1. If there is a right node in node 1, then 3 will be added to the stack and the answer, and finally pop, and then return the answer.

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> res;
        if (root == nullptr) {
            return res;
        }

        stack<TreeNode*> st;
        TreeNode* node = root;
        while(node!=nullptr||!st.empty())
        {
            while(node!=nullptr)
            {
                //遍历左子树
                st.push(node);
                res.push_back(node->val);
                node=node->left;
            }
            //遍历了左子树,就要取节点然后遍历右子树了
            node=st.top();
            st.pop();
            node=node->right;
        }
        return res;
    }
};

94. Inorder Traversal of Binary Tree - LeetCode

Given the root node of a binary tree root, return its inorder traversal .

Example 1:

输入:root = [1,null,2,3]
输出:[1,3,2]

Example 2:

输入:root = []
输出:[]

Example 3:

输入:root = [1]
输出:[1]

Recursive version:

class Solution {
public:
    vector<int>res;
    vector<int> inorderTraversal(TreeNode* root) {
        inorder(root);
        return res;
    }

    void inorder(TreeNode* root)
    {
        if(root==nullptr) return;
        inorder(root->left);
        res.push_back(root->val);
        inorder(root->right);
    }
    
};

Non-recursive version:

Also for a tree as shown in the figure

Inorder traversal: left center right

6 4 2 5 1 3is the answer to inorder traversal.

The difference between in-order traversal and pre-order traversal in the non-recursive way is that the value of the node cannot be added to the answer when the road loops through the left subtree, but can only be added to the stack. Wait until the left subtree is finished before the current node can be added to the answer, then continue to take the nodes in the stack, then pop the nodes in the stack, and then go to the right node.

class Solution {
public:
    vector<int>res;
    stack<TreeNode*> st;
    vector<int> inorderTraversal(TreeNode* root) {
        if(root==nullptr) return res;

        TreeNode* node=root;
        while(node!=nullptr||!st.empty())
        {
            while(node!=nullptr)
            {
                st.push(node);
                node=node->left;
            }
            node=st.top();
            st.pop();
            res.push_back(node->val);
            node=node->right;
        }
        return res;
    }
};

145. Postorder Traversal of Binary Tree - LeetCode

Given the root node of a binary tree root, return the postorder traversal of its node values .

Example 1:

输入:root = [1,null,2,3]
输出:[3,2,1]

Example 2:

输入:root = []
输出:[]

Example 3:

输入:root = [1]
输出:[1]

Directly to the non-recursive version

The most important thing to pay attention to here is to avoid repeatedly adding a node to the answer and finally causing an infinite loop.

Like the pre-order and in-order traversal, the left subtree is finished first, and then the right subtree is judged. If I only judge whether the right subtree is empty, when I go to node 7 and return to node 2, I have to go 2->right at this time. Obviously, 2->right exists, so 4 will be added to the answer and the stack. It will cause an endless loop.

Here you can use a pre node to save the node that was added to the stack last time, and then judge whether it is the same as pre.

class Solution {
public:
    vector<int> postorderTraversal(TreeNode *root) {
        vector<int> res;
        if (root == nullptr) {
            return res;
        }

        stack<TreeNode *> st;//stack
        TreeNode* node=root;//当前节点
        TreeNode *prev = nullptr;//上一次加入答案的节点
        while(node!=nullptr||!st.empty())
        {
            //递归完左区间
            while(node!=nullptr)
            {
                st.push(node);
                node=node->left;
            }
            node=st.top();//取栈顶
            st.pop();//出栈
            //判断是否有右子树
            if(node->right==nullptr||node->right==prev)
            {
                res.push_back(node->val);
                prev=node;//记录每一次加入答案的点,防止重复加入死循环
                node=nullptr;
            }else
            {
                //如果还有右边的节点,就重写把根节点入栈,然后让root指向右节点,让右节点加入答案
                st.push(node);
                node=node->right;
            }
        }
        return res;
    }
};

Guess you like

Origin blog.csdn.net/AkieMo/article/details/131796509