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

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

所有题目首先考虑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. 词嵌入之FastText

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

  2. LTH7锂电池充放电IC完整方案

    内容目录: A,LTH7贴片5脚充电芯片    PW4054 1, 单节的锂电池保护电路     单节为3.7V锂电池(也叫4.2V)和3.8V锂电池(也叫4.35V) 2, 单节的锂电池充电电路   ...

  3. Spring Cloud Alibaba学习笔记

    引自B站楠哥:https://space.bilibili.com/434617924 一.创建父工程 创建父工程hello-spring-cloud-alibaba Spring Cloud Ali ...

  4. uni-app开发经验分享十七: 开发微信公众号(H5)JSSDK 的使用方式

    因为这个jssdk被uni-app坑了好多天,作者说支持1.4版本,但是我用1.4的两个分享的新方法一直不支持. 最后只能放弃了,期待什么时候能更新上. 基本的使用方法:第一步 - 下载使用方式下载地 ...

  5. python系统监控及邮件发送

    python系统监控及邮件发送   #psutil模块是一个跨平台库,能轻松实现获取系统运行的进程和系统利用率   import psutil                              ...

  6. 使用Python对MySQL数据库插入二十万条数据

    1.当我们测试的时候需要大量的数据的时候,往往需要我们自己造数据,一条一条的加是不现实的,这时候就需要使用脚本来批量生成数据了. import pymysql import random import ...

  7. Java层面上下文切换

    前言 在过去单CPU时代,单任务在一个时间点只能执行单一程序.之后发展到多任务阶段,计算机能在同一时间点并行执行多任务或多进程.虽然并不是真正意义上的"同一时间点",而是 多个任务 ...

  8. 每天响应数亿次请求,腾讯云如何提供高可用API服务?

    每天响应数亿次请求,腾讯云如何提供高可用API服务? https://mp.weixin.qq.com/s/OPwlHcqkaTT_gcwHfr5Shw 李阳 云加社区 2020-09-16 导语 | ...

  9. all header field names in both HTTP requests and HTTP responses are case-insensitive.

    https://tools.ietf.org/html/rfc6455#section-4.2.1 Please note that according to [RFC2616], all heade ...

  10. 洛谷 P1401 城市

    写在前面 今天来水主题库里的有水分的紫题,随便一翻竟然找到宝了. 小清新二分 + 网络流. 算法思路 考虑到题目中限制的是最大边权,要求最大边权最小,那么很容易想到二分答案. 单调性的证明:最大边权是 ...