[TOC]
前言
上篇博客我带大家领略了一番链式二叉树的操作,现在让我们来看看二叉树的相关题目,一起来巩固一下知识点吧!
点我复习上一篇博客的内容!👉传送门
1.一些选择题
1.1
1 | 设一棵二叉树中有3个叶子结点,有8个度为1的结点,则该二叉树中总的结点数为( )个 |
设Ni表示度为i的节点个数,则节点总数 N = N0 + N1 + N2
节点个数于节点边的关系: N个节点的树有N-1个边
边与度的关系:N - 1 = N1 + 2 * N2
故:N0 + N1 + N2 - 1 = N1 + 2 * N2
因此,得:N0 = N2 + 1
回到原题,N0 = 3,N1 = 8,可得N2 = 2
因此答案是 3 + 8 + 2 = 13
1.2
1 | 有N个元素的完全二叉树的深度是() |
高度为h的完全二叉树,节点个数在: 2^(h - 1) - 1 < n <= 2^h - 1
即log(n + 1) <= h < log(n + 1) + 1
这里需要注意的是n左右区间的开闭问题
完全二叉树最少的节点个数是2^(h - 1)-1+1
个,所以是n>2^(h - 1) - 1
1.3 由已知遍历序列画出原本树的结构
1 | 已知某二叉树的中序遍历序列为JGDHKBAELIMCF,后序遍历序列为JGKHDBLMIEFCA,则其前序遍历序列为( ) |
这道题我刚开始的思路是错的,因为我把它当作完全二叉树来看待,但题目并没有说它是完全二叉树
主要思路:可以从后续遍历确定根节点为A,中序遍历可以确定A的左右子树。再继续从后序遍历中确定A左右子树的根节点,依次往下判断
所以我画了一个分析图,如下👇
1 | 已知某二叉树的前序遍历序列为ABDEC,中序遍历序列为BDEAC,则该二叉树( ) |
这道题的思路和上一道题是一样的
1 | 已知某二叉树的前序遍历序列为5 7 4 9 6 2 1,中序遍历序列为4 7 5 6 9 1 2,则其后序遍历序列为( ) |
本题依旧和上面两道题思路相同!
1.4 单边树
1 | 一棵非空的二叉树的先序遍历序列与后序遍历序列正好相反,则该二叉树一定满足( ) |
如果前序遍历和后序遍历序列正好相反,说明它是一个单边树,比如下面这前序和中序序列所构成的树的结构:
12345(纵向)
54321
对于单边树,只有一个叶子节点
1.5
1 | 20.如果一颗二叉树的前序遍历的结果是ABCD,则满足条件的不同的二叉树有( )种 |
首先这棵二叉树的高度一定在3~4层之间:
三层:
A(B(C,D),()), A((),B(C,D)), A(B(C,()),D), A(B((),C),D),
A(B,C(D,())), A(B,C((),D))
四层:
如果为四层,就是单边树,每一层只有一个节点,除过根节点,其他节点都有两种选择,在上层节点的左边还是右边,所以222共8种
总共为14种。
2.OJ题刷起来!
KY11 二叉树遍历
牛客网 KY11 二叉树遍历 👉传送门
这道题要求我们用先序遍历的操作从一个数组中读出一个树,并构建出树的基本结构,再用中序遍历的方式打印出这颗树
之前我们学习了前序遍历的操作,这里只需要把前序遍历中的printf操作改成构建新树即可
- 因为涉及道i的多次调用,所以函数中的i需要取地址,必须保证多次调用的i会同步++
- 构建完树的节点,并赋值后,需要递归构建左右子树,最后返回节点的地址
- 题目中的#代表NULL,直接return空即可
1 |
|
100 相同的树
leetcode:100. 相同的树
题目要求很简单,给定两颗树的根节点,要求我们判断这两棵树是否相同
- 如果两棵树都为空,树相同
- 如果其中一个为空,另外一个不为空,树不同
- 如果两个都不为空,但是节点值不相同,树不同
- 然后再递归判断左子树和右子树,将它们的结果与
&&
在一起,其中一个为假,返回假
1 | bool isSameTree(struct TreeNode* p, struct TreeNode* q){ |
学会这道题后,后面一些题目其实只需要把它的代码改一改就能用了😂
什么?你不信?那就看看下面这道题!
101 对称二叉树
leetcode:101. 对称二叉树
题目要求很简单哈,判断是不是两边对称的树
这和判断树相等有什么区别呢?不就是把左右子树的判断改一下就行了嘛?
直接调用上一题的代码!注意最后的return值,是p的左和q的右进行判断
1 | bool _isSameTree(struct TreeNode* p, struct TreeNode* q){ |
哈哈,是不是很爽,别急,后面还有可以偷懒的题目!
572 另外一棵树的子树
leetcode:572. 另一棵树的子树
这道题我们要判断一颗树是否为另外一棵树的子树,和判断一个字符串是不是另外一个字符串的子串很相似
其实只需要递归判断每一个节点的左右子树是否和subRoot
相同就可以了!
1 | bool _isSameTree(struct TreeNode* p, struct TreeNode* q){ |
是不是爽起来了?再来一道!
226 翻转二叉树
leetcode:226. 翻转二叉树
这道题的思路如下哈!
- 如果是空树,不需要翻转,直接return
- 如果非空,就把该节点的左右子树交换(这里不需要担心交换后找不到子树的问题)
- 不需要单独搞空的子树,一并交换就可以
- 当根节点为空的时候,return
啪的一下很快哈,代码就写出来了!
1 | void _invertTree(struct TreeNode* root) |
102 层序遍历(较难😥)
leetcode:102. 二叉树的层序遍历
这道题相对来说就么有那么容易了,你可能和我一样,压根没看明白题目要求中的后两个参数是用来干嘛的
1 | /** |
看了一些题解,这才算理解了这道题的要求
*returnSize
:存放的是二叉树的层数**returnColumnSizes
:存放的是二叉树每一层的节点个数- 返回值要求是
int**
:需要返回一个指针数组,该数组中的每一个元素是一个数组A,数组A保存了二叉树每一层的节点值
0.错误思路
最开始我的想法是,用单独的函数计算出树的节点个数和层级,再进行一次层序遍历来得到树的值。
但很显然,这一思路在本题是搞不通的!🤔
1.数组队列初始化
在上一篇博客中,我讲述了利用队列来实现层序遍历的思路。这道OJ题目我们也是这么干的。不同的是,在我自己写的队列实现里,使用的是链式队列。而本题使用数组队列会好一点!
1 |
|
2.初始化数组
这部分会毕竟绕,先一步一步来理解
1 | *returnSize = 0;//将二叉树层级初始化为0 |
ret
是一个指针数组,存放的是数组A,数组A里面是每一层的节点值。ret也就是题目要求的返回值*returnColumnSizes
开辟一个数组来保存每一层的节点数
这里其实returnColumnSizes
没有啥二级指针的必要,但是既然题目给了是int**
,我们就需要先*
解引用再malloc开辟数组
3.队列操作思路
- 先让根节点入队列,tail++
- 外层循环判断队列是否非空,如果非空就停止操作
- 内层循环进行每一层的入队操作,这样才能得到每一层的节点值和节点个数
- 在内层循环中创建ret数组的子数组,单独存放每一层的节点值
- 最后将每一层的节点个数赋值给
*returnColumnSizes
数组,*returnSize++
一次
1 | struct TreeNode* head; |
外层循环结束后,此时ret数组就是题目要求的结果了,返回ret就可以了!
这里有一个小问题,当树为空树时,层级应该是0。所以我们需要在第一行赋值
*returnSize = 0;
不然会执行出错
这道题的思路是我看过题解之后才搞明白的,所以上面的只是一个思路的复现😭还是太菜了!
结语
本篇刷题笔记到这里就结束啦,如果对涉及到的题目有什么不懂的地方,可以在评论区提出哦!
要是知道,OJ也能偷懒,嘿嘿嘿嘿……😂
不过最后一道题是真的难,我还以为它和前中后序遍历一样,只是让我们遍历出数组的值呢🙃
- 本文标题:【C语言】带你用偷懒的方式刷爆二叉树OJ题
- 创建时间:2022-04-20 19:16:49
- 本文链接:posts/4165981723/
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!