主要是深度遍历和层序遍历的递归和迭代写法。

另外注意:因为求深度可以从上到下去查 所以需要前序遍历(中左右),而高度只能从下到上去查,所以只能后序遍历(左右中)。

所有题目首先考虑root否是空。有的需要考虑root是否是范围内合理的起点。其他细节:每次需要引用节点值时考虑是否非空。

基本概念:

  • 二叉树节点的深度:从上数第几层:指从根->该节点的最长简单路径边的条数。
  • 二叉树节点的高度:从下数第几层:指从节点->叶子节点的最长简单路径边的条数。

leetcode144.二叉树的前序遍历

递归较容易,迭代即每次访问stack的top,把左右非空的压进去即可注意左右入栈顺序

leetcode145.二叉树的后序遍历

递归类似。迭代直接写较复杂,转换为先序(左右调换),结果倒序输出。

leetcode94.二叉树的中序遍历

递归类似前序。

迭代时因为访问和路过不同,所以用cur做路线,stack做访问,stack以空开始,cur先把最左一路全部压入,再pop读值,然后cur转到右边第一个。

迭代容易写错

可以while嵌套while

stack = []
cur = root
while cur or stack:
while cur:
stack.append(cur)
cur = cur.left
cur = stack.pop()
nums.append(cur.val)
cur = cur.right

也可以用while (if else)

stack = []
cur = root
while cur or stack:
if cur:
stack.append(cur)
cur = cur.left
else:
cur = stack.pop()
nums.append(cur.val)
cur = cur.right

leetcode102.二叉树的层序遍历

用双端队列。注意点:队列先入先出,故左先右后。此外,要先看deque的长度再循环,因为其长度是变化的。

 while deque_tree:
len_que = len(deque_tree) #注意
res_temp = []
for i in range(len_que):
cur = deque_tree.popleft()
res_temp.append(cur.val)
if cur.left != None: #注意
deque_tree.append(cur.left)
if cur.right != None:
deque_tree.append(cur.right)

类似题目:107,199,637,429, 104, 559,513

leetcode226.翻转二叉树

即将二叉树每个点的的左右孩子交换。要点:每个点都要遍历到且只到一次。

建议使用前/后序遍历和层序遍历,简单且直观。不能使用中序遍历。

leetcode101.对称二叉树

判断左右子树是否对称。此题deque中可以存在空,这样不用单独判断第一个节点,处理比较方便。所以在循环中需要根据空/非空判断,重点是处理左右均是空时不更新deque,至少有一个非空时判断是否对称;全部非空才更新deque。

关键代码:

stack = []
stack.append(root.left)
stack.append(root.right) while stack:
cur_right = stack.pop()
cur_left = stack.pop()
if (not cur_left) and (not cur_right):
continue
if ((not cur_left) and cur_right) or ((not cur_right) and cur_left) or cur_right.val != cur_left.val:
return False
stack.append(cur_left.left) #注意cur_left和cur_right顺序 与pop一致
stack.append(cur_right.right)
stack.append(cur_left.right)
stack.append(cur_right.left)

leetcode104.二叉树最大深度

迭代法:层序遍历

递归法:节点深度等于左右子树深度中最大的加1

类似题目:559 n叉树最大深度

leetcode111.二叉树最小深度

迭代法:层序遍历。注意每到新的一层直接更新1,遇到叶子节点return

    while deque_tree:
len_que = len(deque_tree)
min_dep += 1 #注意
for i in range(len_que):
cur = deque_tree.popleft()
if (not cur.left) and (not cur.right):
return min_dep
if cur.left:
deque_tree.append(cur.left)
if cur.right:
deque_tree.append(cur.right)

递归:不能到None返回,子树为空时深度为0,但不合题因为非叶子节点。所以可以把0去掉:

def mindep(root):
if not root:
return 0
left = mindep(root.left)
right = mindep(root.right)
if left == 0 or right == 0:
return max(left, right)+1
else:
return min(left,right)+1

leetcode110.平衡二叉树

要求判断二叉树是否平衡,即左子树深度和右子书深度差不大于1。

因为是依靠深度判断,所以是后序遍历。递归返回深度,如果不平衡则返回-1标记(注意保持有一个是-1即返回-1)

    def traverse(root):
if not root:
return 1
leftdepth = traverse(root.left)
rightdepth = traverse(root.right)
if leftdepth==-1 or rightdepth==-1 or abs(rightdepth-leftdepth)>1:
return -1
else:
return max(leftdepth, rightdepth)+1

leetcode257.找所有的路径

要求找二叉树根到所有叶子节点的路径。需要使用回溯,但还没学到,以后可以重新审视。

迭代法:遍历节点,放在stack中的元素为元组(root, path_temp),后者记录到该节点的路径。注意更新stack时要将数值转为str再合并。

递归法:要想清楚架构。递归不反回值,主要通过递归修改res。每个点需要的参数有root, 上层路径path及需要修改的res。每次遇到叶子节点时进行修改。

def getpaths(self, root, path,res):
if (not root.left) and (not root.right):
res_temp = ''
for i in range(len(path)):
res_temp += str(path[i].val)+'->'
res_temp += str(root.val)
res.append(res_temp)
return
else:
if root.left: #注意
self.getpaths(root.left,path+str(root.val),res)
if root.right: #注意
self.getpaths(root.right,path+str(root.val),res)

leetcode112.路径总和

判断跟->叶子节点的路径和中是否有等于给定目标值的。

迭代法:跟257类似,stack中元素改为(root, sums),判断是否是叶子节点。

递归法:和257类似。返回bool_left or bool_right,因为有一个存在即有。注意如果left是空时,为False,right同理。

leetcode113.路径总和II

找到所有路径和等于目标值的路径。是112和257的结合。

迭代法:同257,只是每次到叶子节点需要判断一下再存。

递归法:同257,注意path传入时不要给path赋值,因为是list所以相当于“指针”,不要修改。

leetcode100.是否是相同的树

迭代递归均可。主要注意空非空的考虑。

leetcode572.是否是子树

先对到根节点,再套用leetcode100判断是否相同。

leetcode404.左叶子之和

判断:1.是叶子节点。2:是左叶子。因此需要上一个节点,或上一个节点的信息。

递归和迭代均即可。迭代时存上一个节点不好存,所以可以放在stack中:(root,bool_isleft)来指示。注意取出时需要分别把root和boil_isleft取出

leetcode106.从中序和后序序列构造二叉树

递归法:从后序序列的最后一个确定中间节点,切割递归。注意取出序列时用pop.

需要方法:list.index()确定索引值的索引

leetcode105.从中序与前序序列构造二叉树

同106。拓展:如只有前和后序,能否构造二叉树?不能。信息量一样,都只能确定中间,没法确定左右顺序。举例可举两个关于镜像的二叉树

类似题目 654

leetcode617. 合并二叉树

将两个二叉树合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。

递归较容易。

迭代:stack中均非空,按其左右分类讨论

leetcode700.二叉搜索树寻值

迭代:利用二叉搜索树的结构。

递归:在确定向左还是向右时注意谁是被寻的值

leetcode98.验证二叉搜索树

即验证中序遍历或序列是否是递增的。

leetcode530.BST的最小绝对差

BST类题目的中点是相当于在递增数组上操作,因为其中序遍历即是递增数组。因此该题可以中序遍历BST,算绝对值差

易错点:需要记录上一个节点,每次都要记录。而在判断值时才需要判断上一个节点是否非空。此外,中序遍历的迭代写法的最后一步直接写cur  = cur.right, 因为在开头会顾忌其是否非空的判断,无需多想。

leetcode501.BST的众数

虽然本题是求BST的众数,作为拓展,分为求BST众数和一般二叉树众数的求解。

对BST:依然是考虑为递增数组,需判断与上一个节点是否相同来决定计数。当数值等于最大时,加入结果中;数值大于最大时,将结果清空(list.clear()),再加入结果。

对一般二叉树:遍历数组,把结果存到字典中,key:value=number:count。重点在对字典排序。

dict_tree_sorted = sorted(dict_tree.items(), key = lambda x:x[1], reverse = True)

三个要点:1.函数sorted。2.将字典的元素的集合变成列表,列表中的元素形式为元组:dict.items()。3.隐函数确定key key = lambda x:x[1]。lambda后无冒号。

此外,在循环中,取字典中的值为dict.get()

leetcode236.最近的公共祖先

该题有一定难度,需要复习!需要复习!需要复习!

题目明确,两个元素都在树中存在(如果没有该限制,则考虑加全局的bool判断是否全部存在)。因为最近的公共祖先(即最低的,翻译问题)最低,所以在遍历时应从底向上遍历,因此考虑后序遍历。如果是空,则返回空;是两元素之一,则返回两元素之一。在处理中间节点时,分为两种情况:1.若左右均空,则返回空。2.若有至少一个非空:若两个均非空,则返回root;如有一个非空,则返回非空的。因此,如果两个在两支上,则返回连接点;若在同一支,则返回较高的。另一个角度,在高处只有一支有,所以只有一支的情况包含了两元素在同一支的情况和遍历到较高点的情况。

class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': if not root or root == q or root == p:
return root left_node = self.lowestCommonAncestor(root.left, p, q)
right_node = self.lowestCommonAncestor(root.right, p, q) if left_node or right_node:
if left_node and right_node:
return root
else:
return left_node or right_node
else:
return None

leetcode235.BST最近的祖先

不需要像一般二叉树需要从底层向上遍历。从上到下遍历时,只要当前值在两元素区间内(注意是闭区间),则该点即是要找的节点。

leetcode701.BST插入节点

直接插到符合条件的空节点处即可。从root开始,按大小关系找到空节点,每一步要记录上一节点。

leetcode450.BST删除节点

删除节点有很多细节需要处理。首先从整体思路上考虑,删除节点时首先判断该节点的子树是单支还是双支:如果是单支,则直接把单支并到前一个节点上;如果是双支,则需要把左支并到右支的最左边(因为所有右边的元素均大于左边),再将右支并到左支。注意到,需要前一个节点,则细节1:需要删除的是根节点时,则前一个节点为空,需要单独处理。易错点:该题分类比较麻烦,最后分完类要记得return。写完检查一下每一类是否都有return对应的情况。

leetcode669.BST减枝

修剪BST,使得BST的节点值都在[low high]范围内。一个常见的错误思路是找到一个区间内的点作为root起点,如果左节点小于low就直接将左支删掉,右节点类似。产生该错误的主要原因是虽然左支的数都比中间的小,注意是比中间的小,而不是比low小,直接删除左支不可取,右支同理。

正确的思路是:找到一个合乎区间的点作为root。先处理左枝:如果左支小于low,则删除比左支小的部分,即将左节点替换为左节点的右节点(注意不是根的右节点),继续判断。如果左节点在区间内,则将cur移到左节点,重复刚才的判断——摸石头过河,一步一步拓展。右枝的处理同理。

易错点:在找合乎区间的root时,注意如果该点比low小,则向右。方向容易搞错。

leetcode108.有序数组构造BST

每次将中间的元素构造节点,左枝等于中间左边部分,右枝等于中间右边部分。

leetcode538.BST转化为累加树

将BST每个节点的值转化为大于等于其值的和。因为是大于等于,所以相当于是本身的值加上右边所有节点的值(包括父节点和右子树),因此即右中左遍历,每个节点的值等于该节点的值加上上一节点的值(因为上一节点的值已经是之前的和)即可。

leetcode_二叉树篇_python的更多相关文章

  1. 数据结构之二叉树篇卷三 -- 二叉树非递归遍历(With Java)

    Nonrecursive Traversal of Binary Tree First I wanna talk about why we should <code>Stack</c ...

  2. 数据结构之二叉树篇卷一 -- 建立二叉树(With Java)

    一.定义二叉树节点类 package tree; public class Node<E> { public E data; public Node<E> lnode; pub ...

  3. 数据结构之二叉树篇卷四 -- 二叉树线索化(With Java)

    一.线索二叉树简介 二叉树本身是一种非线性结构,然而当你对二叉树进行遍历时,你会发现遍历结果是一个线性序列.这个序列中的节点存在前驱后继关系.因此,如何将这种前驱后继信息赋予给原本的二叉树呢?这就是二 ...

  4. leetcode_二叉树验证(BFS、哈希集合)

    题目描述: 二叉树上有 n 个节点,按从 0 到 n - 1 编号,其中节点 i 的两个子节点分别是 leftChild[i] 和 rightChild[i]. 只有 所有 节点能够形成且 只 形成 ...

  5. 数据结构之二叉树篇卷二 -- 二叉树递归遍历(With Java)

    一.先序递归遍历(Preorder Recursive Traversal) 1.1 算法 首先需要明确的是这里的序是针对 root 节点而言的.故先序即先“访问”根节点,其次“访问”其左右节点. 1 ...

  6. Python笔记_第五篇_Python数据分析基础教程_文件的读写

    1. 读写文件(基本) savetxt.loadtxt i2 = np.eye(2) print(i2) np.savetxt(r"C:\Users\Thomas\Desktop\eye.t ...

  7. Python笔记_第五篇_Python数据分析基础教程_NumPy基础

    1. NumPy的基础使用涵盖如下内容: 数据类型 数组类型 类型转换 创建数组 数组索引 数组切片 改变维度 2. NumPy数组对象: NumPy中的ndarray是一个多维数组对象,该兑现共有两 ...

  8. Python笔记_第五篇_Python数据分析基础教程_相关安装和版本查看

    1. IDE说明: 所有的案例用Anacoda中的Jupiter工具进行交互式讲解. 2. 版本和安装: NumPy从如下网站安装:http://sourceforge.net/projects/nu ...

  9. Python笔记_第五篇_Python数据分析基础教程_前言

    1. 前言: 本部分会讲解在Python环境下进行数值运算.以NumPy为核心,并讲解其他相关库的使用,诸如Matplotlib等绘图工具等. C.C++和Forttran等变成语言各有各的优势,但是 ...

随机推荐

  1. ctfhub技能树—文件上传—00截断

    什么是00截断 相关教程:http://www.admintony.com/%E5%85%B3%E4%BA%8E%E4%B8%8A%E4%BC%A0%E4%B8%AD%E7%9A%8400%E6%88 ...

  2. 词嵌入之FastText

    什么是FastText FastText是Facebook于2016年开源的一个词向量计算和文本分类工具,它提出了子词嵌入的方法,试图在词嵌入向量中引入构词信息.一般情况下,使用fastText进行文 ...

  3. Linux学习安装

    Linux学习安装 服务器指的是网络中能对其他机器提供某些服务的计算机系统,相对普通PC, 服务器指的是高性能计算机,稳定性.安全性要求更高 linux安装学习 1.虚拟机 一台硬件的机器 安装vmw ...

  4. 無法直接連接互聯網,需要使用代理時(Scrapy)

    在windows系統中,如果無法直接連接互聯網,需要使用代理時該怎麽做呢? 1. 在powershell中設置proxy 背景:使用公司電腦,無法直接訪問互聯網,想要訪問互聯網就得使用代理,但是在控制 ...

  5. C++ /Python 将视频中的片段转为图片

      配置OpenCV :项目名称->右击->属性 VC++目录 包含目录 放 ...\build\include ...\build\include\opencv   ...\build\ ...

  6. 一文打尽 Linux/Windows端口复用实战

    出品|MS08067实验室(www.ms08067.com) 本文作者:Spark(Ms08067内网安全小组成员) 定义:端口复用是指不同的应用程序使用相同端口进行通讯. 场景:内网渗透中,搭建隧道 ...

  7. QQ好友状态,QQ群友状态,究竟是推还是拉? 网页端收消息,究竟是推还是拉?

    https://mp.weixin.qq.com/s/KB1zdKcsh4PXXuJh4xb_Zw 网页端收消息,究竟是推还是拉? 原创 58沈剑 架构师之路 2020-12-28   https:/ ...

  8. (转载)微软数据挖掘算法:Microsoft 神经网络分析算法原理篇(9)

    前言 本篇文章继续我们的微软挖掘系列算法总结,前几篇文章已经将相关的主要算法做了详细的介绍,我为了展示方便,特地的整理了一个目录提纲篇:大数据时代:深入浅出微软数据挖掘算法总结连载,有兴趣的童鞋可以点 ...

  9. java native:Java本地方法调用(jni方式)

    https://www.cnblogs.com/zh1164/p/6283831.html

  10. springboot2.2.2集成6.5 Elasticsearch

    1.0POM文件 <!-- spring-boot --> <dependency> <groupId>org.springframework.boot</g ...