数据结构:二叉树OJ题(基础版)

前言

更完两期二叉树的知识之后,来做几道oj题巩固一下基础


一、翻转二叉树

链接:leetcode链接

还是分治思想,将问题分解成左子树和右子树交换,遇到空树停止

采用递归算法做题

C++ 复制代码
 TreeNode* invertTree(TreeNode* root) {
        if(root == nullptr)
        return nullptr;

        swap(root->left,root->right);

        invertTree(root->left);
        invertTree(root->right);

        return root;
    }

二、另一棵树的子树

链接:leetcode链接

我们可以分解子问题,是不是当前树的子树,是不是左子树的子树,是不是右子树的子树。

细节:如果不是当前树的子树,不应该返回false,而应该继续在左右子树寻找

C++ 复制代码
bool isSame(TreeNode* a,TreeNode* b)
    {
        if(a == nullptr && b == nullptr)
        return true;

        if(a == nullptr || b == nullptr)
        return false;

        if(a->val != b->val)
        return false;

        return isSame(a->left,b->left)
            && isSame(a->right,b->right);
    }

    bool isSubtree(TreeNode* root, TreeNode* subRoot) {
        if(root == nullptr)
        return false;

        if(root->val == subRoot->val)
        {
            bool ret = isSame(root,subRoot);
            if(ret) return true;
        }

        return isSubtree(root->left,subRoot)
            || isSubtree(root->right,subRoot);
    }

三、二叉树的构建及遍历

链接:牛客链接

思路:

中序遍历很简单,很容易实现

这里,比较难的地方是,如何从先序遍历的序列中构建出二叉树

ok,我的思路是这样的:

先去构建当前树,再去构建左子树,再去构建右子树,符合先序遍历的顺序

很明显,这又是一个递归算法。

那么核心就是如何构建好当前树

遇到'#',就代表遇到空节点,遇到其他字符,就正常构建

注意:要传参控制string的下标,不然,没办法结束。

C++ 复制代码
#include <iostream>
using namespace std;


struct TreeNode
{
    TreeNode* left = nullptr;
    TreeNode* right = nullptr;
    char val;
};


TreeNode* Creater(string& s,int& i)
{
    TreeNode* root = new TreeNode;
    if(s[i] == '#')
    {
    i++;
    return nullptr;
    }

    root->val = s[i++];

    root->left = Creater(s, i);
    root->right = Creater(s, i);

    return root;
}

void InOrder(TreeNode* root)
{
    if(root == nullptr)
    return ;

    InOrder(root->left);
    cout << root->val << " ";
    InOrder(root->right);
}

int main() {
   string s;
   cin >> s;
   int i = 0;
   TreeNode* root = Creater(s,i);
   InOrder(root);
   cout << endl;
   return 0;
}

四、对称二叉树链接:

链接:leetcode链接

思路:我们这样想,如何比较两棵树是否对称呢?

记为root_a树和root_b树

显然,需要

(1) root_a树的根节点与root_b树的根节点值相等

(2) 需要root_a树的左子树和root_b树的右子树相等

(3) 需要root_a树的右子树和root_b树的左子树相等

空树为最小子问题

C++ 复制代码
 bool isMirror(TreeNode* left, TreeNode* right) {
       if(left == nullptr && right == nullptr)
       return true;

       if(left == nullptr || right == nullptr)
       return false;

       if(left->val != right->val)
       return false;

       return isMirror(left->left,right->right)
           && isMirror(left->right,right->left);
    }

    bool isSymmetric(TreeNode* root) {
        if (root == nullptr)
            return true;

        return isMirror(root->left,root->right);
    }

五、层序遍历

链接:leetcode链接

注意:该题目不仅仅是层序遍历,另外要求将每一层分开输出。
核心点在于,如何在层序遍历时区分二叉树每一层

层序遍历时的规律:

用队列存储节点,

可以发现,每次出完一层之后,

恰好下一层的所有节点正好进入队列

也就是队列中剩余元素的个数就是下一层的节点的个数

(读者可尝试自己画图分析)

依照次规律,我们可以另外设置一个变量,来记录每一层需要输出的个数。

C++ 复制代码
vector<vector<int>> levelOrder(TreeNode* root) {
        queue<TreeNode*> q;
        if(root == nullptr)
        return {};
        vector<vector<int>> vv;
        q.push(root);
        
        int levelSize = 1;

        while(!q.empty())
        {
            vector<int> v;
            while(levelSize--)
            {
            TreeNode* front = q.front();
            q.pop();
            v.push_back(front->val);

            if(front->left)  q.push(front->left);
            if(front->right) q.push(front->right);
            }

            levelSize = q.size();
            vv.push_back(v);
        }

        return vv;
    }

六、判断是不是完全二叉树

链接:牛客链接

思路:

根据完全二叉树层序遍历的规律

出完上一层的同时,下一层全部进入队列

所以,我们可以这么操作

我们不管出队列的节点的左节点和右节点是否为nullptr,都进入队列。

当我们出到nullptr的时候,我们就跳出循环

去检查队列中剩余的元素

如果有非空元素,则并不是完全二叉树,如果全部都是空,则是完全二叉树。

为什么可以这么操作呢?

当我们出到nullptr的时候,如果后面有非空节点,那么他一定是nullptr节点前面节点的子节点,他一定进入了队列。

(这点理解清楚,这道题目就没问题了,读者可以画图尝试理解)

C++ 复制代码
bool isCompleteTree(TreeNode* root) {
        queue<TreeNode*> q;
        q.push(root);

        while(!q.empty())
        {
            TreeNode* front = q.front();
            q.pop();

            if(front != nullptr)
            {
                q.push(front->left);
                q.push(front->right);
            }
            else break;
        }

        while(!q.empty())
        {
            TreeNode* front = q.front();
            if(front != nullptr)
            return false;
            q.pop();
        }

        return true;
    }

ok,先讲着6个题目吧,后面更复杂的题目,会在后续博客中进行更新

相关推荐
爱吃生蚝的于勒27 分钟前
深入学习指针(5)!!!!!!!!!!!!!!!
c语言·开发语言·数据结构·学习·计算机网络·算法
羊小猪~~30 分钟前
数据结构C语言描述2(图文结合)--有头单链表,无头单链表(两种方法),链表反转、有序链表构建、排序等操作,考研可看
c语言·数据结构·c++·考研·算法·链表·visual studio
脉牛杂德1 小时前
多项式加法——C语言
数据结构·c++·算法
一直学习永不止步2 小时前
LeetCode题练习与总结:赎金信--383
java·数据结构·算法·leetcode·字符串·哈希表·计数
wheeldown9 小时前
【数据结构】选择排序
数据结构·算法·排序算法
躺不平的理查德13 小时前
数据结构-链表【chapter1】【c语言版】
c语言·开发语言·数据结构·链表·visual studio
阿洵Rain14 小时前
【C++】哈希
数据结构·c++·算法·list·哈希算法
Leo.yuan14 小时前
39页PDF | 华为数据架构建设交流材料(限免下载)
数据结构·华为
半夜不咋不困14 小时前
单链表OJ题(3):合并两个有序链表、链表分割、链表的回文结构
数据结构·链表
忘梓.15 小时前
排序的秘密(1)——排序简介以及插入排序
数据结构·c++·算法·排序算法