【数据结构】二叉树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);
}










相关文章
|
2天前
|
C语言
【数据结构】二叉树(c语言)(附源码)
本文介绍了如何使用链式结构实现二叉树的基本功能,包括前序、中序、后序和层序遍历,统计节点个数和树的高度,查找节点,判断是否为完全二叉树,以及销毁二叉树。通过手动创建一棵二叉树,详细讲解了每个功能的实现方法和代码示例,帮助读者深入理解递归和数据结构的应用。
28 8
|
26天前
|
存储 Java
数据结构第三篇【链表的相关知识点一及在线OJ习题】
数据结构第三篇【链表的相关知识点一及在线OJ习题】
23 7
|
25天前
|
存储 算法 关系型数据库
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
这篇文章主要介绍了多路查找树的基本概念,包括二叉树的局限性、多叉树的优化、B树及其变体(如2-3树、B+树、B*树)的特点和应用,旨在帮助读者理解这些数据结构在文件系统和数据库系统中的重要性和效率。
16 0
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
|
25天前
|
存储 算法 搜索推荐
数据结构与算法学习十七:顺序储存二叉树、线索化二叉树
这篇文章主要介绍了顺序存储二叉树和线索化二叉树的概念、特点、实现方式以及应用场景。
15 0
数据结构与算法学习十七:顺序储存二叉树、线索化二叉树
|
26天前
|
Java
【用Java学习数据结构系列】震惊,二叉树原来是要这么学习的(二)
【用Java学习数据结构系列】震惊,二叉树原来是要这么学习的(二)
25 1
|
26天前
|
算法 Java C语言
【用Java学习数据结构系列】震惊,二叉树原来是要这么学习的(一)
【用Java学习数据结构系列】震惊,二叉树原来是要这么学习的(一)
22 1
|
25天前
|
存储 算法
探索数据结构:分支的世界之二叉树与堆
探索数据结构:分支的世界之二叉树与堆
|
25天前
|
存储 算法
数据结构与算法学习十六:树的知识、二叉树、二叉树的遍历(前序、中序、后序、层次)、二叉树的查找(前序、中序、后序、层次)、二叉树的删除
这篇文章主要介绍了树和二叉树的基础知识,包括树的存储方式、二叉树的定义、遍历方法(前序、中序、后序、层次遍历),以及二叉树的查找和删除操作。
21 0
|
3天前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
45 9
|
1天前
|
存储
系统调用处理程序在内核栈中保存了哪些上下文信息?
【10月更文挑战第29天】系统调用处理程序在内核栈中保存的这些上下文信息对于保证系统调用的正确执行和用户程序的正常恢复至关重要。通过准确地保存和恢复这些信息,操作系统能够实现用户模式和内核模式之间的无缝切换,为用户程序提供稳定、可靠的系统服务。
20 4