【数据结构】二叉树OJ练习2

简介: 【数据结构】二叉树OJ练习

四、另一棵树的子树


链接572. 另一棵树的子树


描述:


给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。


二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。


示例1:

64e2d152fdeb70791b3ee456d764bc68.jpeg


输入:root = [3,4,5,1,2], subRoot = [4,1,2]
输出:true


示例2

30b875a4c6a4746dfb841b407945c0f9.png

输入:root = [3,4,5,1,2,null,null,null,null,0], subRoot = [4,1,2]
输出:false


提示:


   root 树上的节点数量范围是 [1, 2000]

   subRoot 树上的节点数量范围是 [1, 1000]

   -10^4 <= root.val <= 10^4

   -10^4 <= subRoot.val <= 10^4


思路:


这道题算是 相同的树 的进阶版,如果没有我们上一题的铺垫,这题会写的很烦。

我们的主体思路是判断 二叉树的每一棵子树是否和 subRoot 相等。



那么给出我们主要决策:


   由于 subRoot 一定不为空,所以一旦 root的子树为空,则返回假;

   如果 root 的子树 和 subRoot 相等,那么返回真;

   否则 递归左右子树,左右子树中任意一边找到了则 子树存在 。


而这里我们判断是否相等就可以直接复用 相同的树 了。


1569766e37a4745d7514d0c4fc2d1395.png

完整代码:

bool isSameTree(struct TreeNode* p, struct TreeNode* q)
{
    if (p == NULL && q == NULL)
    {
        return true;
    }
    if (p == NULL || q == NULL)
    {
        return false;
    }
    if (p->val != q->val)
    {
        return false;
    }
    return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}
bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot)
{
    // 子树不为空,如果树为空,则为假
    if (root == NULL)
    {
        return false;
    }
    // 如果找到了子树,则直接返回
    if (isSameTree(root, subRoot))
    {
        return true;
    }
    // 分别递归左右子树,子树只要找到了,则存在
    return isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot);
}



五、翻转二叉树


链接226. 翻转二叉树


描述

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

示例1

980aacbef5daac6ffeb1aa0d4dc6061b.jpeg

输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]

示例2

7f9c19bae52a1f2ea61b0cdfe4a30b2a.jpeg

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


示例3

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



提示:

   树中节点数目范围在 [0, 100] 内

   -100 <= Node.val <= 100


思路:


对于翻转二叉树,就是把一棵树所有的左右子树对调,这里我们可以使用 后序遍历 的思想。

那么我们基本就可以写出我们的思路:


如果节点为空,那么无需翻转,返回 NULL;


否则就先递归左子树,再递归右子树,到底后,开始交换左右子树,最后逐层返回。


c0c51eaf11e44aed81ca7b898d75bda5.png


463e50804525b67e14d307bd8910b4b8.png



六、对称二叉树


链接101. 对称二叉树


描述


给你一个二叉树的根节点 root , 检查它是否轴对称。


示例1


4d04ed26478244f429c257acec46354a.jpeg



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



示例2

b2715f82d410e78db5fa693101743297.jpeg

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


提示:


  • 树中节点数目在范围 [1, 1000]
  • -100 <= Node.val <= 100

思路1


一棵树是否轴对称,可以理解为 它的根节点的 某一边子树翻转 后是否和另一边为 相同的树

比如我们这边翻转左子树:

cad1a99cbbe999781166444d201ae2cb.png


我们上方 相同的树 和 翻转二叉树 刚刚写过,那么写这种思路就很简单了。


这题我们也给出相应的决策:


   如果左右子树都为空,为根节点,那么返回真;

   如果左右子树一遍不为空,那么返回假;

   如果左右子树都不为空,那么给定 left 和 right 分别记录左右子树。翻转左边,记录右边;

   最后返回判断左右子树是否为相同的树。


接下来我们看看代码怎么写:

struct TreeNode* invertTree(struct TreeNode* root)
{
    if (root == NULL)
    {
        return NULL;
    }
    struct TreeNode* left = invertTree(root->left);
    struct TreeNode* right = invertTree(root->right);
    root->left = right;
    root->right = left;
    return root;
}
bool isSameTree(struct TreeNode* p, struct TreeNode* q)
{
    if (p == NULL && q == NULL)
    {
        return true;
    }
    if (p == NULL || q == NULL)
    {
        return false;
    }
    if (p->val != q->val)
    {
        return false;
    }
    return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}
bool isSymmetric(struct TreeNode* root)
{
    // 左右子树都为空
    if (root->left == NULL && root->right == NULL)
    {
        return true;
    }
    // 左右子树一边不为空
    if (root->left == NULL || root->right == NULL)
    {
        return false;
    }
    // 左右子树两边都不为空
    struct TreeNode* left, *right;
    if (root->left && root->right)
    {
        // 翻转左边
        left = invertTree(root->left);
        right = root->right;
    }
    // 和右边子树比较,返回 bool 值
    return isSameTree(left, right);
}


730c98f8819e31aa8a77be3ddff720d9.png



   但是这种方法也是不太好的,因为破坏了原本二叉树的结构,那么还有更好的方法吗?看思路2。

思路2:


一棵树对称就是 它的左右子树呈镜像状态 。说白了就是节点左子树的值等于右子树的值,右子树的值等于左子树的值。


那么我们可以用一个 check 函数来递归检查,并将二叉树的根节点传两份过去:


   如果两棵树都为空,返回真;

   如果两棵树一棵为空,另一棵不为空,返回假;

   如果两棵树都不为空,但是值不相等,返回假;

   上面的走完都没有返回,那么就分别递归第一棵树的左子树和第二棵树的右子树;第一棵树的右子树和第二棵树的左子树。


最后返回 check 函数的真值,就能判断出结果。


7674bb51843c83aa314fc30669566d89.png



七、二叉树的前序遍历


链接144. 二叉树的前序遍历


描述


给你二叉树的根节点 root ,返回它节点值的 前序 遍历。


示例 1

84e85756605d69b9890cd72995f6c0bb.jpeg

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



示例 2:

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


示例3

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



示例 4:


5c471b0a166b5077a2b76a7ba1c9e592.jpeg


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


示例 5

f96d49e7d1ed47bd9749ae85e8dab07a.jpeg


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


提示:


   树中节点数目在范围 [0, 100] 内

   -100 <= Node.val <= 100


思路:


这里的前序遍历和之前的有所不同,题目要求我们将遍历结果存到数组中,将数组返回,且空指针不需要记录。


那么我们可以计算出二叉树的大小,然后 动态开辟一个二叉树大小的数组。

并使用一个下标来记录数组的元素个数,最后 前序遍历二叉树 ,将结果存入数组,返回数组。


e9e86ac3c2fe184ca57b34025aee7f41.png


相关题目



相关题目和这道题思路类似,我就不带着大家看了,大家自己下去可以试试



八、平衡二叉树



链接110. 平衡二叉树


描述

给定一个二叉树,判断它是否是高度平衡的二叉树。


本题中,一棵高度平衡二叉树定义为:

一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。

示例1

06dad7b5ecbd49dc2c6e52f556b7fc17.jpeg


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


示例2


bffa58a6f1ca8a82291dac35708a64b8.jpeg

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


示例3

输入:root = []
输出:true



提示:

   树中的节点数在范围 [0, 5000] 内

   -104 <= Node.val <= 104


思路:


所谓 平衡二叉树就是任意节点的子树的高度差都小于等于1。


基于这个理解,那么我们可以将它分成子问题:每个节点的子树的高度差小于等于1。


那么就可以给出思路:


   如果节点为空,则是完全二叉树;

   否则就求左右两边子树高度;

   再判断左右子树的 高度差的绝对值 是否 大于1 ,大于1则一定不是完全二叉树,返回假;

   最后分别递归左右子树,判断左右子树是否满足完全二叉树的条件。


求高度的就是我们上篇博客的 计算二叉树的高度 的接口。


a741d1a019412650385498eb2ba2e6ff.png



完整代码:


int TreeHeight(struct TreeNode* root)
{
    if (root == NULL)
    {
        return 0;
    }
    int leftHeight = TreeHeight(root->left);
    int rightHeight = TreeHeight(root->right);
    return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}
bool isBalanced(struct TreeNode* root)
{
    // 根节点为空,是完全二叉树
    if (root == NULL)
    {
        return true;
    }
    // 求左右两边高度
    int leftHeight = TreeHeight(root->left);
    int rightHeight = TreeHeight(root->right);
    // 绝对值大于1一定不是完全二叉树
    if (abs(leftHeight - rightHeight) > 1)
    {
        return false;
    }
    return isBalanced(root->left) && isBalanced(root->right);
}










目录
打赏
0
0
0
0
9
分享
相关文章
☀☀☀☀☀☀☀有关栈和队列应用的oj题讲解☼☼☼☼☼☼☼
### 简介 本文介绍了三种数据结构的实现方法:用两个队列实现栈、用两个栈实现队列以及设计循环队列。具体思路如下: 1. **用两个队列实现栈**: - 插入元素时,选择非空队列进行插入。 - 移除栈顶元素时,将非空队列中的元素依次转移到另一个队列,直到只剩下一个元素,然后弹出该元素。 - 判空条件为两个队列均为空。 2. **用两个栈实现队列**: - 插入元素时,选择非空栈进行插入。 - 移除队首元素时,将非空栈中的元素依次转移到另一个栈,再将这些元素重新放回原栈以保持顺序。 - 判空条件为两个栈均为空。
|
2月前
|
【C++数据结构——树】二叉树的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现二叉树的基本运算。​ 相关知识 创建二叉树 销毁二叉树 查找结点 求二叉树的高度 输出二叉树 //二叉树节点结构体定义 structTreeNode{ intval; TreeNode*left; TreeNode*right; TreeNode(intx):val(x),left(NULL),right(NULL){} }; 创建二叉树 //创建二叉树函数(简单示例,手动构建) TreeNode*create
59 12
|
2月前
|
C++
【C++数据结构——树】二叉树的性质(头歌实践教学平台习题)【合集】
本文档介绍了如何根据二叉树的括号表示串创建二叉树,并计算其结点个数、叶子结点个数、某结点的层次和二叉树的宽度。主要内容包括: 1. **定义二叉树节点结构体**:定义了包含节点值、左子节点指针和右子节点指针的结构体。 2. **实现构建二叉树的函数**:通过解析括号表示串,递归地构建二叉树的各个节点及其子树。 3. **使用示例**:展示了如何调用 `buildTree` 函数构建二叉树并进行简单验证。 4. **计算二叉树属性**: - 计算二叉树节点个数。 - 计算二叉树叶子节点个数。 - 计算某节点的层次。 - 计算二叉树的宽度。 最后,提供了测试说明及通关代
53 10
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
55 2
数据结构中二叉树,哈希表,顺序表,链表的比较补充
二叉搜索树,哈希表,顺序表,链表的特点的比较
数据结构中二叉树,哈希表,顺序表,链表的比较补充
数据结构实验之二叉树实验基础
本实验旨在掌握二叉树的基本特性和遍历算法,包括先序、中序、后序的递归与非递归遍历方法。通过编程实践,加深对二叉树结构的理解,学习如何计算二叉树的深度、叶子节点数等属性。实验内容涉及创建二叉树、实现各种遍历算法及求解特定节点数量。
138 4
|
4月前
|
【数据结构】二叉树(c语言)(附源码)
本文介绍了如何使用链式结构实现二叉树的基本功能,包括前序、中序、后序和层序遍历,统计节点个数和树的高度,查找节点,判断是否为完全二叉树,以及销毁二叉树。通过手动创建一棵二叉树,详细讲解了每个功能的实现方法和代码示例,帮助读者深入理解递归和数据结构的应用。
229 8
探索数据结构:分支的世界之二叉树与堆
探索数据结构:分支的世界之二叉树与堆
|
4月前
|
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
374 9
|
4月前
|
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
64 1
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等