二叉树
二叉树是数据结构中重要的一个章节,他的重要性也不言而喻,在未来不管是笔试还是面试都会遇到这类的题目,所以接下来我就会把一些常考的题目全部整理出来供大家学习指正。

点击下面链接即可进行刷题学习
开始刷题
先说明一下一些题目取自牛客网面试必刷TOP101
里面的一些题目在我以前的文章详细写到过,如果没有用新的方法就不会再做讲解
LeetCode刷题 —— 手撕二叉树
题目链接
描述
给定一个二叉树根节点,请你判断这棵树是不是二叉搜索树。
二叉搜索树满足每个节点的左子树上的所有节点均严格小于当前节点且右子树上的所有节点均严格大于当前节点。
例:
图1:

图2:

数据范围:节点数量满足1 ≤ n ≤ 10^4,节点上的值满足1 ≤ val ≤ 2^31−1
示例1
输入:{1,2,3}
返回值:false
说明:如题面图1
示例2
输入:{2,1,3}
返回值:true
说明:如题面图2
思路分析:
对于这种搜索树有一个规律:
使用中序遍历就会发现他是递增的,所以我们利用这个性质,使用中序遍历:先遍历左子树,在判断root的值是否大于左子树,不是则返回false,再递归右子树。为了判断大小得加一个全局变量pre。
#include <limits.h>
static long pre = INT_MIN;
bool isValidBST(struct TreeNode* root ) {
if(!root)
{
return true;
}
//进入左子树
if(!isValidBST(root->left))
{
return false;
}
if(root->val <= pre)
{
return false;
}
//更新pre值
pre = root->val;
//进入右子树
if(!isValidBST(root->right))
{
return false;
}
return true;
}
接下来画图理解:
对于这棵树:


题目链接
描述
给定一个二叉树,确定他是否是一个完全二叉树。
完全二叉树的定义:若二叉树的深度为 h,除第 h 层外,其它各层的结点数都达到最大个数,第 h 层所有的叶子结点都连续集中在最左边,这就是完全二叉树。(第 h 层可能包含 [1~2h] 个节点)
数据范围:节点数满足1 ≤ n ≤ 100
样例图1:

样例图2:

样例图3:

示例1
输入:{1,2,3,4,5,6}
返回值:true
示例2
输入:{1,2,3,4,5,6,7}
返回值:true
示例3
输入:{1,2,3,4,5,#,6}
返回值:false
思路分析:
根据完全二叉树性质可以发现如果走层序遍历,只要遇到NULL,后边的一定全部为NULL,如果后面出现不为NULL的,一定不是完全二叉树,前面知道层序遍历得用栈。
typedef struct TreeNode* QDateType;
typedef struct QueueNode
{
struct QueueNode* next;
QDateType date;
}QueueNode;
typedef struct Queue
{
QueueNode* head;
QueueNode* tail;
}Queue;
bool QueueEmpty(Queue* pst);
void QueueInit(Queue* pst)
{
pst->head = pst->tail = NULL;
}
void QueueDestroy(Queue* pst)
{
QueueNode* cur = pst->head;
while (cur)
{
QueueNode* next = cur->next;
free(cur);
cur = next;
}
pst->head = pst->tail = NULL;
}
void QueuePush(Queue* pst, QDateType x)
{
QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
if (newnode == NULL)
{
printf("malloc fail\n");
exit(-1);
}
newnode->date = x;
newnode->next = NULL;
if (pst->head == NULL)
{
pst->head = newnode;
pst->tail = newnode;
}
else
{
pst->tail->next = newnode;
pst->tail = newnode;
}
}
void QueuePop(Queue* pst)
{
if (pst->head->next == NULL)
{
free(pst->head);
pst->head = pst->tail = NULL;
}
else
{
QueueNode* next = pst->head->next;
free(pst->head);
pst->head = next;
}
}
QDateType QueueBack(Queue* pst)
{
return pst->tail->date;
}
QDateType QueueFront(Queue* pst)
{
return pst->head->date;
}
//真返回非0
bool QueueEmpty(Queue* pst)
{
return pst->head == NULL;
}
int QueueSize(Queue* pst)
{
QueueNode* cur = pst->head;
int size = 0;
while (cur)
{
size++;
cur = cur->next;
}
return size;
}
bool isCompleteTree(struct TreeNode* root ) {
Queue q;
QueueInit(&q);
QueuePush(&q, root);
while(!QueueEmpty(&q))
{
struct TreeNode* tmp = QueueFront(&q);
QueuePop(&q);
if(tmp == NULL)
{
//后边必须全部为NULL
while(!QueueEmpty(&q))
{
if(QueueFront(&q) != NULL)
{
return false;
}
QueuePop(&q);
}
return true;
}
else
{
QueuePush(&q, tmp->left);
QueuePush(&q, tmp->right);
}
}
return true;
}
描述
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
1.对于该题的最近的公共祖先定义:对于有根树T的两个节点p、q,最近公共祖先LCA(T,p,q)表示一个节点x,满足x是p和q的祖先且x的深度尽可能大。在这里,一个节点也可以是它自己的祖先.
2.二叉搜索树是若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值; 若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值
3.所有节点的值都是唯一的。
4.p、q 为不同节点且均存在于给定的二叉搜索树中。
数据范围:
3<=节点总数<=10000
0<=节点值<=10000
如果给定以下搜索二叉树: {7,1,12,0,4,11,14,#,#,3,5},如下图:

示例1
输入:{7,1,12,0,4,11,14,#,#,3,5},1,12
返回值:7
说明:节点1 和 节点12的最近公共祖先是7
示例2
输入:{7,1,12,0,4,11,14,#,#,3,5},12,11
返回值:12
说明:因为一个节点也可以是它自己的祖先.所以输出12
思路分析:
利用好搜索二叉树的性质:要找到目标值,如果该节点比目标小,则向右子树寻找,反之向左子树寻找。
那么我们可以通过两个数组保存两个路径,最后遍历两个数组,最后一个相等的数值就为公共节点(前面一定相等)
void AdjustArr(struct TreeNode* root, int p, int* arr, int* l)
{
if(!root)
{
return;
}
if(root->val < p)
{
arr[*l] = root->val;
(*l)++;
AdjustArr(root->right, p, arr, l);
}
else if(root->val > p)
{
arr[*l] = root->val;
(*l)++;
AdjustArr(root->left, p, arr, l);
}
else
{
arr[*l] = root->val;
(*l)++;
return;
}
}
int lowestCommonAncestor(struct TreeNode* root, int p, int q ) {
int* arr1 = (int*)malloc(sizeof(int) * 1000);
//记录长度
int l1 = 0;
AdjustArr(root, p, arr1 , &l1);
int* arr2 = (int*)malloc(sizeof(int) * 1000);
//记录长度
int l2 = 0;
AdjustArr(root, q, arr2 , &l2);
//遍历两个数组,找到第一个不同的点
int ret = 0;
for(int i = 0; i < l1 && i < l2; i++)
{
if(arr1[i] == arr2[i])
{
ret = arr1[i];
}
else
{
break;
}
}
return ret;
}
如果p和q都小于当前数值,则公共祖先一定在左子树上,如果p和q都大于当前节点,则公共祖先一定在右子树上,如果一个大于一个小于,则该节点就是公共祖先节点。
int lowestCommonAncestor(struct TreeNode* root, int p, int q ) {
if(root->val < p && root->val < q)
{
return lowestCommonAncestor(root->right, p, q);
}
else if(root->val > p && root->val > q)
{
return lowestCommonAncestor(root->left, p, q);
}
else
{
return root->val;
}
}
用递归图理解一下:

我们可以看到二叉树基本解题思路就是递归,如果递归想不出代码,可以直接看最后一步怎么实现,其次一定要多画图理解。
点击链接一起刷题吧
HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候
1.在Python3中,下列关于数学运算结果正确的是:(B)a=10b=3print(a//b)print(a%b)print(a/b)A.3,3,3.3333...B.3,1,3.3333...C.3.3333...,3.3333...,3D.3.3333...,1,3.3333...解析: 在Python中,//表示地板除(向下取整),%表示取余,/表示除(Python2向下取整返回3)2.如下程序Python2会打印多少个数:(D)k=1000whilek>1: print(k)k=k/2A.1000 B.10C.11D.9解析: 按照题意每次循环K/2,直到K值小于等
我一直在尝试在Ruby中实现BinaryTree类,但我得到了stackleveltoodeep错误,尽管我似乎没有在该特定代码段中使用任何递归:1.classBinaryTree2.includeEnumerable3.4.attr_accessor:value5.6.definitialize(value=nil)7.@value=value8.@left=BinaryTree.new#stackleveltoodeephere9.@right=BinaryTree.new#andhere10.end11.12.defempty?13.(self.value==nil)?true:
西安华为OD面试体验开始投简历技术面试进展工作进展开始投简历去年一整年一直在考研和工作之间纠结,感觉自己的状态好像当时的疫情一样差劲。之前刚毕业的时候投了个大厂的简历,结果一面写算法的时候太拉跨了,虽然知道时dfs但是代码熟练度不够,放在平时给足时间自己可以调试通过,但是熟练度不够那面试当时就写不出来被刷了。说真的算法学到后期我感觉最重要的是熟练度和背板子(对于我这种普通玩家来说),面试题如果一上来短时间内想不出思路就完蛋了。然后由于当时找的工作不是很理想就又想考研了。但是考研是有风险的,我自我感觉自己可能冲不上那个学校,而找工作一个没成可以继续找嘛。本着抱着试试看的态度在boss上投了简历,
首先,这是我的版本:Greg-Nowickis-MacBook-Pro:sample_appGreg_Nowicki$ruby-vruby2.0.0p451(2014-02-24revision45167)[x86_64-darwin13.1.0]Greg-Nowickis-MacBook-Pro:sample_appGreg_Nowicki$rails-vRails4.0.4我正在学习HartlRails教程并安装rspec进行测试。我已将gem'rspec-rails'添加到我的gemfile中,当我运行railsgeneraterspec:install时,这就是我得到的:Gre
点击->操作系统复习的文章集目录操作系统线程线程是什么进程与线程的关系用户态/内核态操作系统资源管理内核态用户态内核态/用户态切换程序运行类型分析计算密集型IO密集型结合进程,线程来理解程序运行类型分析协程基础上下文切换协程协程为什么叫协作式线程?协程的优缺点操作系统线程典型问题:简述进程和线程的区别以下内容带您一步步了解线程是什么比进程更小的独立运行的基本单位-线程(Threads)线程的提出主要是为了提高系统内程序并发执行的程度,从而进一步提升系统的吞吐量,充分发挥多核CPU的优越性而设计的引入进程是为了操作系统更加方便地管理程序,使得多个程序能并发管理和执行而线程则是为了减少程序在并发执
文章目录华为OD面试流程1.mysql数据库建了两个字段,且设置了联合索引,如果其中有一个字段为空会出现什么问题?2.谈谈springIOC的理解,有什么好处,解决了什么问题3.谈谈springAOP的理解,切面编程有没有实际应用,有哪些注解,作用是什么,有那些应用场景?4.Erika和zookeeper有了解过吗,作用是什么,主要解决了什么问题5.谈谈JDK、JRE、JVM的理解,区别是什么6.谈谈对泛型的理解7.JVM的组成华为OD面试流程机试:三道算法题,关于机试,橡皮擦已经准备好了各语言专栏,可以直接订阅。性格测试:机试技术一面(本专栏核心)技术二面(本专栏核心)主管面试定级定薪发of
我正在关注RyanBatesScreenCast#360Facebook身份验证...当我到达点击链接登录facebook的部分时,我得到一个{"error":{"message":"Missingclient_idparameter.","type":"OAuthException","code":101}}我尝试像之前所说的那样重新启动服务器我正在拔头发试图弄清楚这一点我在facebook开发页面上的网站url是正确的我已经按照他的步骤数百次 最佳答案 可能是你没有为FACEBOOK_KEY和FACEBOOK_SECRET设置e
1,Camera基本工作原理答案:光线通过镜头Lens进入摄像头内部,然后经过IRFilter过滤红外光,最后到达sensor(传感器),senor分为按照材质可以分为CMOS和CCD两种,可以将光学信号转换为电信号,再通过内部的ADC电路转换为数字信号,然后传输给DSP(如果有的话,如果没有则以DVP的方式传送数据到基带芯片baseband,此时的数据格式RawData,后面有讲进行加工)加工处理,转换成RGB、YUV等格式输出。数据流是如何从sensor到APP的?上述描述结束后,在ISP处理后面的阶段,数据会进行分流,分为capture,preview,video等以供后续动作使用。例如
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭11年前。我是一名经验丰富的网络开发人员,但只有一点点Ruby/Rails经验。我周一刚在一家Ruby商店接受面试,他们确实意识到我没有太多Ruby经验。除了我手边的2或3本Ruby书籍外,我还可以利用哪些其他资源来参加周末的Ruby速成类。顺便说一下,我在hostingrails上确实有一个最低限度的帐户,尽管我从未使用过它。我没有看到任何其他与搜索“rubyi