Detailed explanation of classic algorithm problems on binary trees (very detailed)

Table of contents

Question 1: The height of a binary tree

Question 2: Calculate the number of nodes in the tree

Question 3 single-valued binary tree

Question 4 The same tree

Question 5: Preorder traversal of binary tree

Question 6: Flip Binary Tree

Question 7 Symmetric Binary Tree 

Question 8: Subtree of another tree

Question 9 Create a binary tree and traverse it


Question 1: The height of a binary tree

Enter the root node of a binary tree and find the depth of the tree. The nodes (including root and leaf nodes) passed in sequence from the root node to the leaf nodes form a path of the tree, and the length of the longest path is the depth of the tree.

class Solution {
public:
    int maxDepth(TreeNode* root) {
        if(root==NULL){
            return 0;
        }
        int left_hign=maxDepth(root->left);
        int right_hign=maxDepth(root->right);
        return left_hign>right_hign?left_hign+1 : right_hign+1;
    }
};

Question 2: Calculate the number of nodes in the tree

Given the root node root of a complete binary tree, find the number of nodes in the tree.

The definition of a complete binary tree is as follows: In a complete binary tree, except for the bottom node, which may not be filled, the number of nodes in each layer reaches the maximum, and the nodes in the bottom layer are concentrated in the leftmost positions of the layer. If the lowest layer is the h-th layer, then this layer contains 1~2h nodes.

class Solution {
public:
    int countNodes(TreeNode* root) {
        if(root==nullptr){
            return 0;
        }

        return countNodes(root->left)+countNodes(root->right)+1;
    }
};

Question 3 single-valued binary tree

If each node of a binary tree has the same value, then the binary tree is a single-valued binary tree.

It is returned only if the given tree is a single-valued binary tree  true; otherwise it is returned  false.

class Solution {
public:
    bool isUnivalTree(TreeNode* root) {
        if(root==nullptr){
            return true;
        }
        if(root->left&&root->val!=root->left->val){
            return false;
        }
        if(root->right&&root->val!=root->right->val){
            return false;
        }
        // else{
        //     return true;//写了这个的话就没办法往下递归了
        // }

            return isUnivalTree(root->left)&&isUnivalTree(root->right);
    }
};

Question 4 The same tree

Given the sum of the root nodes of two binary trees  p ,  q write a function to test whether the two trees are the same.

Two trees are considered identical if they are structurally identical and have nodes with the same values.

class Solution {
public:
    bool isSameTree(TreeNode* p, TreeNode* q) {
        if(p==nullptr&&q==nullptr){//都为空
            return true;
        }
        else if(p==nullptr||q==nullptr){//一空一有
            return false;
        }

        else if(p->val!=q->val){//都有
            return false;
        }
        else {     //如果当前节点没有问题,那么向下递归
            return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
        }

}
};

Question 5: Preorder traversal of binary tree

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> ret;
        preoreder(ret,root);
        return ret;
        }
    void preoreder(vector<int> &ret,TreeNode* cur){
        if(cur==nullptr){
            return ;
        }
        else{
            ret.push_back(cur->val);
        }
        preoreder(ret,cur->left);
        preoreder(ret,cur->right);
    }
};

Question 6: Flip Binary Tree

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        invert(root);
        return root;
    }

    void invert(TreeNode*  cur){
        if(cur==nullptr){//注意是两个等于号
            return ;
        }
        TreeNode* tmp=cur->right;
        cur->right=cur->left;
        cur->left=tmp;
        invert(cur->right);
        invert(cur->left);
    }
};

A small optimization

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        invert(root);
        return root;
    }

    void invert(TreeNode*& cur){//尽量使用传引用
        if(cur==nullptr){
            return ;
        }
        TreeNode* tmp=cur->right;
        cur->right=cur->left;
        cur->left=tmp;
        invert(cur->right);
        invert(cur->left);
    }
};

Question 7 Symmetric Binary Tree 

recursive method

We can implement such a recursive function to traverse the tree by "synchronously moving" two pointers. Both the p pointer and the pointer point to the root of the tree at the beginning. Then when p moves to the right, q moves to the left, and p moves to the left. When moving, q moves to the right. Each time, check whether the values ​​of the current p and q nodes are equal, and if so, determine whether the left and right subtrees are symmetrical.

class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        if(root==nullptr){
            return true;
        }
        return isSym(root,root);
    }

    bool isSym(TreeNode*& left,TreeNode*& right){
        if (!left && !right) return true;//我要让空进去,所以对两个空连续取反
        if (!left || !right) return false;//一空一非空
        return left->val == right->val && isSym(left->left, right->right) && isSym(left->right, right->left);
    }

};

Iterative method

Earlier we used the recursive method to realize the symmetry judgment, so how to use the iterative method to realize it? First we introduce a queue, which is a common method to rewrite recursive programs into iterative programs. During initialization we enqueue the root node twice. Extract two nodes each time and compare their values ​​(every two consecutive nodes in the queue should be equal, and their subtrees are mirror images of each other), and then press the left and right sub-nodes of the two nodes in reverse order Inserted into the queue in order. The algorithm ends when the queue is empty, or when we detect tree asymmetry (i.e. two unequal consecutive nodes are taken from the queue).

class Solution {
public:
    bool check(TreeNode *u, TreeNode *v) {
        queue <TreeNode*> q;
        q.push(u); q.push(v);
        while (!q.empty()) {
            u = q.front(); q.pop();
            v = q.front(); q.pop();
            if (!u && !v) continue;
            if ((!u || !v) || (u->val != v->val)) return false;

            q.push(u->left); 
            q.push(v->right);

            q.push(u->right); 
            q.push(v->left);
        }
        return true;
    }

    bool isSymmetric(TreeNode* root) {
        return check(root, root);
    }
};

Question 8: Subtree of another tree

class Solution {
public:
    bool isSubtree(TreeNode* root, TreeNode* subRoot) {
        if(root==nullptr){
            return false;
        }
        return isSametree(root,subRoot)||isSubtree(root->left,subRoot)||isSubtree(root->right,subRoot);
//检查当前节点然后按任意序列遍历子树
    }
    bool isSametree(TreeNode* p,TreeNode* q){
        if(!p&&!q){
            return true;
        }
        if(!p||!q){
            return false;
        }

        return p->val==q->val&&isSametree(p->left,q->left)&&isSametree(p->right,q->right);

    }
};

Question 9 Create a binary tree and traverse it

1.C language writing method



#include <stdio.h>
#include <malloc.h>

typedef struct BTNode
{
    char _data;
    struct BTNode* _left;
    struct BTNode* _right;
}BTNode;

//中序遍历
void Inorder(BTNode* root)
{
    if(root)
    {
        Inorder(root->_left);
        printf("%c ", root->_data);
        Inorder(root->_right);
    }
}

BTNode* CreatBTree(char* str, int* pi)
{
    if(str[*pi]!= '#')
    {
        //当前节点非空,则创建当前节点
        BTNode*root=(BTNode*)malloc(sizeof(BTNode));
        root->_data = str[*pi];
        //字符位置向后移动一个位置
        ++(*pi);
        //创建左子树
        root->_left=CreatBTree(str,pi);
        //字符位置向后移动一个位置
        ++(*pi);
        //创建右子树
        root->_right=CreatBTree(str,pi);
        return root;
    }
    else
        return NULL;  //如果是空节点,则返回NULL
}

int main()
{
    char str[101];
    int i = 0;
    //读入字符串
    scanf("%s", str);
    //创建二叉树
    BTNode* root = CreatBTree(str, &i);
    //中序打印二叉树
    Inorder(root);
    printf("\n");
    return 0;
}

2.c++ writing method

#include<string>
using namespace std;
class BTNode {
public:
	char value;//节点值
	BTNode *l;//左孩子
	BTNode *r;//右孩子
	BTNode() {
		value = '0';
		l = NULL;
		r = NULL;
	}
	~BTNode() {
		this->l = NULL; this->r = NULL;
		delete(this);
	}
};
//利用先序遍历构建二叉树
void initBT(BTNode * root) {
	
	//访问结点值
	
	//访问左子树
	char temp = cin.get();
	if (temp == '#') {
		root->l = NULL;
	}
	else {
		BTNode *btn1 = new BTNode();
		btn1->value = temp;
		root->l = btn1;
		initBT(root->l);//接着对左子树先序遍历
	}
	
	//访问右子树
	temp = cin.get();
	if (temp == '#') {
		root->r= NULL;
	}
	else {
		BTNode *btn2 = new BTNode();
		btn2->value = temp;
		root->r = btn2;
		initBT(root->r);//接着对右子树先序遍历
	}

}
//中序遍历并进行输出
void inOrderTravel(BTNode * root) {
	if (root == NULL)return;//空结点,直接返回
	//访问左子树
	if (root->l != NULL) {
		inOrderTravel(root->l);//访问左子树
	}
	//访问结点值
	cout << root->value << " ";
	//访问右子树
	if (root->r != NULL) {
		inOrderTravel(root->r);//访问右子树
	}
}
int main() {
	
	char c = cin.get();
	BTNode *root = new BTNode();
	root->value = c;
	initBT(root);//构建二叉树
	inOrderTravel(root);//中序遍历,并且输出中序序列
	cout << endl;
	return 0;
}

Question 10: Balanced Binary Tree

1. Top-up

class Solution {
public:
    bool isBalanced(TreeNode* root) {

        return isbal(root);
    }

    bool isbal(TreeNode*& cur){
        if(cur==nullptr){
            return true;
        }
        if(abs(tree_high(cur->left)-tree_high(cur->right))<2){
            return true&&isbal(cur->left)&&isbal(cur->right);
        }
        else{
            return false;
        }
    }

    int tree_high(TreeNode*& cur){
        if(cur==nullptr){
            return 0;
        }
        int left_high=tree_high(cur->left);
        int right_high=tree_high(cur->right);
        return left_high>right_high?left_high+1:right_high+1;
    }
};

 This way of writing is more abstract and concise

           return max(height(root->left), height(root->right)) + 1;

Since it is a top-down recursion, the height function will be called repeatedly for the same node 
, resulting in high time complexity. If the bottom-up approach is used, the function 
height will only be called once for each node.

2. Bottom-up (optimization)

The bottom-up recursive approach is similar to post-order traversal. For the currently traversed node, first recursively determine whether its left and right subtrees are balanced, and then determine whether the subtree rooted at the current node is balanced. If a subtree is balanced, return its height (the height must be a non-negative integer), otherwise return −1. If one subtree is unbalanced, the entire binary tree must be unbalanced.

class Solution {
public:
    int height(TreeNode* root) {
        if (root == NULL) {
            return 0;
        }
        int leftHeight = height(root->left);
        int rightHeight = height(root->right);
        if (leftHeight == -1 || rightHeight == -1 || abs(leftHeight - rightHeight) > 1) {
            return -1;
        } else {
            return max(leftHeight, rightHeight) + 1;
        }
    }

    bool isBalanced(TreeNode* root) {
        return height(root) >= 0;
    }
};

Guess you like

Origin blog.csdn.net/m0_74234485/article/details/131586701