二叉树经典算法题详解(灰常详细)

目录

第一题 二叉树的高度

第二题 计算树的节点个数

第三题 单值二叉树

第四题 相同的树

第五题 二叉树的前序遍历

第六题 翻转二叉树

第七题 对称二叉树 

第八题 另一颗树的子树

第九题 创建二叉树并且遍历它


第一题 二叉树的高度

输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。

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;
    }
};

第二题 计算树的节点个数

给你一棵完全二叉树的根节点root ,求出该树的节点个数。

完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。

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

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

第三题 单值二叉树

如果二叉树每个节点都具有相同的值,那么该二叉树就是单值二叉树。

只有给定的树是单值二叉树时,才返回 true;否则返回 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);
    }
};

第四题 相同的树

给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。

如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

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);
        }

}
};

第五题 二叉树的前序遍历

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);
    }
};

第六题 翻转二叉树

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);
    }
};

一个小优化

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);
    }
};

第七题 对称二叉树 

递归法

我们可以实现这样一个递归函数,通过「同步移动」两个指针的方法来遍历这棵树, p指针和  指针一开始都指向这棵树的根,随后 p 右移时,q 左移,p左移时,q右移。每次检查当前 p 和 q 节点的值是否相等,如果相等再判断左右子树是否对称。

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);
    }

};

迭代法

前面我们用递归的方法实现了对称性的判断,那么如何用迭代的方法实现呢?首先我们引入一个队列,这是把递归程序改写成迭代程序的常用方法。初始化时我们把根节点入队两次。每次提取两个结点并比较它们的值(队列中每两个连续的结点应该是相等的,而且它们的子树互为镜像),然后将两个结点的左右子结点按相反的顺序插入队列中。当队列为空时,或者我们检测到树不对称(即从队列中取出两个不相等的连续结点)时,该算法结束。

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);
    }
};

第八题 另一颗树的子树

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);

    }
};

第九题 创建二叉树并且遍历它

1.c语言写法



#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++写法

#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;
}

第十题 平衡二叉树

1.自顶向上

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;
    }
};

 这个写法更抽象也更简洁

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

由于是自顶向下递归,因此对于同一个节点,函数 
height会被重复调用,导致时间复杂度较高。如果使用自底向上的做法,则对于每个节点,函数 
height 只会被调用一次。

2.自底向上(优化)

自底向上递归的做法类似于后序遍历,对于当前遍历到的节点,先递归地判断其左右子树是否平衡,再判断以当前节点为根的子树是否平衡。如果一棵子树是平衡的,则返回其高度(高度一定是非负整数),否则返回 −1。如果存在一棵子树不平衡,则整个二叉树一定不平衡。

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;
    }
};

猜你喜欢

转载自blog.csdn.net/m0_74234485/article/details/131586701
今日推荐