01-重建二叉树
题目描述
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
思路:
在二叉树的前序遍历序列中,第一个数字总是树的根结点的值。但在中序遍历序列中,根结点的值在序列的中间,左子树的结点的值位于根结点的值的左边,而右子树的结点的值位于根结点的值的右边。因此我们需要扫描中序遍历序列,才能找到根结点的值。如下图所示,前序遍历序列的第一个数字1就是根结点的值。扫描中序遍历序列,就能确定根结点的值的位置。根据中序遍历特点,在根结点的值1前面的3个数字都是左子树结点的值,位于1后面的数字都是右子树结点的值。
同样,在前序遍历的序列中,根结点后面的3个数字就是3个左子树结点的值,再后面的所有数字都是右子树结点的值。这样我们就在前序遍历和中序遍历两个序列中,分别找到了左右子树对应的子序列。既然我们已经分别找到了左、右子树的前序遍历序列和中序遍历序列,我们可以用同样的方法分别去构建左右子树。也就是说,接下来的事情可以用递归的方法去完成
问题:如何表示出来?https://blog.csdn.net/weixin_38339143/article/details/79897670
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
# 返回构造的TreeNode根节点
def reConstructBinaryTree(self, pre, tin):
# write code here
if len(pre)==0:
return None
root_data = TreeNode(pre[0])#将根定义成节点的形式
i=tin.index(pre[0])#i=tin.index(root_data.val)#寻找位置将左右子树分开 #返回根节点的索引
root_data.left = self.reConstructBinaryTree(pre[1:1+i],tin[:i])
root_data.right = self.reConstructBinaryTree(pre[1+i:],tin[i+1:])
return root_data
# 实例化
if __name__=='__main__':
pre=[1,2,4,7,3,5,6,8]
tin=[4,7,2,1,5,3,8,6]
demo = Solution()
print(demo.reConstructBinaryTree(pre,tin))
02-二叉树的下一个节点
题目描述
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
分析二叉树的下一个节点,一共有以下情况:
1.二叉树为空,则返回空;
2.节点右孩子存在,则设置一个指针从该节点的右孩子出发,一直沿着指向左子结点的指针找到的叶子节点即为下一个节点;
3.节点不是根节点。如果该节点是其父节点的左孩子,则返回父节点;否则继续向上遍历其父节点的父节点,重复之前的判断,返回结果。代码如下
class Solution:
def GetNext(self, pNode):
if pNode.right:#有右子树
p=pNode.right
while p.left:
p=p.left
return p
while pNode.next:#无右子树,则找第一个当前节点是父节点左孩子的节点
if(pNode.next.left==pNode):
return pNode.next
pNode = pNode.next#沿着父节点向上遍历
return #到了根节点仍没找到,则返回空
03-对称的二叉树
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
/*思路:首先根节点以及其左右子树,左子树的左子树和右子树的右子树相同
- 左子树的右子树和右子树的左子树相同即可,采用递归比较左右节点,然后对左右节点的左右分支进一步递归比较
- 非递归也可,采用栈或队列存取各级子树根节点
递归方法
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isSymmetrical(self, pRoot):
if pRoot is None:
return True
return self.Traversal(pRoot.left,pRoot.right)
def Traversal(self,left, right):
if left is None and right is None:
return True
elif left and right and left.val ==right.val:
return self.Traversal(left.left,right.right) and self.Traversal(left.right,right.left)
else:
return False
03-按照之字形顺序打印二叉树
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
可以用一个队列,一个栈实现 也可用两个栈实现,我用两个栈实现,思路简单一点。
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def Print(self, pRoot):
if pRoot is None:
return []
queue=[]
queue.append(pRoot)#把根节点存储在队列
result=[]#存储树有多少层,1,2,3,4之类
while len(queue)!=0:
res=[] #存储每层节点
nextStack=[] #存储左右子树节点
for i in queue:
res.append(i.val)
if i.left:
nextStack.append(i.left)
if i.right:
nextStack.append(i.right)
queue=nextStack
result.append(res)
returnResult=[]
for i, v in enumerate(result):
if i%2==0:
returnResult.append(v)
else:
returnResult.append(v[::-1])
return returnResult
04-把二叉树打印成多行
题目描述
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def Print(self, pRoot):
if pRoot is None:
return []
queue=[]
queue.append(pRoot)#把根节点存储在队列
result=[]#存储树有多少层,1,2,3,4之类
while len(queue)!=0:
res=[] #存储每层节点
nextStack=[] #存储左右子树节点
for i in queue:
res.append(i.val)
if i.left:
nextStack.append(i.left)
if i.right:
nextStack.append(i.right)
queue=nextStack
result.append(res) #这里得到是每一层,和每一层对应的节点
return result
05-序列化二叉树
题目描述
请实现两个函数,分别用来序列化和反序列化二叉树
题目分析: 序列化是层次遍历吗
反序列化是什么意思?
对于序列化:使用前序遍历,递归的将二叉树的值转化为字符,并且在每次二叉树的结点
不为空时,在转化val所得的字符之后添加一个’ , '作为分割。对于空节点则以 ‘#’ 代替。
2. 对于反序列化:按照前序顺序,递归的使用字符串中的字符创建一个二叉树(特别注意:
在递归时,递归函数的参数一定要是char ** ,这样才能保证每次递归后指向字符串的指针会
随着递归的进行而移动!!!)
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def __init__(self):
self.flag = -1
def Serialize(self, root):
# write code here
if not root:
return '#,'
return str(root.val)+','+self.Serialize(root.left)+self.Serialize(root.right)
def Deserialize(self, s):
# write code here
self.flag += 1
l = s.split(',')
if self.flag >= len(s):
return None
root = None
if l[self.flag] != '#':
root = TreeNode(int(l[self.flag]))
root.left = self.Deserialize(s)
root.right = self.Deserialize(s)
return root
06-打印二叉树
题目描述
从上往下打印出二叉树的每个节点,同层节点从左至右打印
思路: 二叉树的层次遍历 先计算出根节点的左右子树,借助一个队列,再循环递归
思路还是很清晰的,使用两个队列一个存放节点,一个存放值。先将根节点加入到队列中,然后遍历队列中的元素,遍历过程中,访问该元素的左右节点,再将左右子节点加入到队列中来
广搜的套路就是用一个队列保存将要搜索的这一层的元素,然后逐个搜索;
1、将第一个元素加入队列
2、队列不为空时取队首元素
3、将下一层元素加入队尾
4、调到第二步,直到队列为空
root 是根节点
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回从上到下每个节点值列表,例:[1,2,3]
def PrintFromTopToBottom(self, root):
if root is None:
return []
queue=[]
result=[]
queue.append(root)
while len(queue)>0:
root=queue.pop(0)
result.append(root.val)
if root.left is not None:
queue.append(root.left)
if root.right is not None:
queue.append(root.right)
return result
07-判断结果
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
思路:
- 二叉树的后序遍历 先左节点再是右节点,最后是根节点
2.二叉搜索树是对一个有序数组进行二分查找形成的搜索树,它指一棵空树或者具有下列性质的二叉树:
若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值; 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
任意节点的左、右子树也分别为二叉查找树;
以下图二叉树为例,我们都知道对二叉搜索树进行中序遍历可以还原为一个有序数组,而图中二叉树后序遍历结果为[3,2,4,6,8,7,5]。接下来分析一下这个数组的规律。首先按照后序遍历的性质,数组的最后一个元素即是整个二叉树的根结点。另外按照搜索二叉树的前两条性质,左子树均小于根,右子树均大于根。左右子树部分同样符合整个规律,所以我们可以递归实现数组的判断。
# -*- coding:utf-8 -*-
class Solution:
def VerifySquenceOfBST(self, sequence):
# write code here
if len(sequence) == 0:
return False
else:
root = sequence[-1]
del sequence[-1]
lefttree = []
righttree =[]
# 左子树和右子树分界
splitindex = -1
for i in range(len(sequence)):
# 值小于根结点的归为左子树
if sequence[i] < root:
lefttree.append(sequence[i])
splitindex = i
else:
break
for i in range(splitindex+1, len(sequence)):
# 若右子树部分有小于根结点的值,说明不是二叉搜索树
if sequence[i] > root:
righttree.append(sequence[i])
else:
return False
if len(lefttree) <= 1:
left = True
else:
# 递归判断左子树
left = self.VerifySquenceOfBST(lefttree)
if len(righttree) <= 1:
right = True
else:
right = self.VerifySquenceOfBST(righttree)
return left and right
08-二叉搜索树的第k个节点
给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。
思路分析:
进行深度遍历–然后存到列表里,
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回对应节点TreeNode
def KthNode(self, pRoot, k):
self.res=[]
self.dfs(pRoot)
if 0<k<=len(self.res):
return self.res[k-1]
else:
return None
def dfs(self,root):
if not root:return
self.dfs(root.left)
self.res.append(root)
self.dfs(root.right)
树的子结构
输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
**> 解题思路
我的弯路 分别获取A和B的前序遍历数组和中序遍历数组——>
比较B的前序遍历数组是否按序在A的前序遍历数组中;比较B的中序遍历数组是否按序在A的中序遍历数组中;
正确思路 遍历二叉树A,定位B的根节点在A中的可能位置——> 定位后,验证B是不是A当前位置的子结构。**
本题的思路在于子结构的判断,首先需要判断两棵树的根节点是否相同,若是不同则递归调用其左子树和B树,若仍不同则递归调用其右子树和B树,若都不同则返回false。
原文:https://blog.csdn.net/u010005281/article/details/79460325 --完整测试代码
1.先在A中找和B的根节点相同的结点
2.找到之后遍历对应位置的其他结点,直到B中结点遍历完,都相同时,则B是A的子树
3.对应位置的结点不相同时,退出继续在A中寻找和B的根节点相同的结点,重复步骤,直到有任何一棵二叉树为空退出
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def HasSubtree(self, pRoot1, pRoot2):
if pRoot1==None or pRoot2==None:
return False
result=False
if pRoot1.val==pRoot2.val:
result=self.isSubtree(pRoot1,pRoot2)
if result==False:
result=self.HasSubtree(pRoot1.left,pRoot2)|self.HasSubtree(pRoot1.right,pRoot2)
return result
def isSubtree(self,root1,root2):
#该函数判断在找到和子树根节点相同的节点之后,判断其余节点是否相同
if root2==None:
return True
if root1==None:
return False
if root1.val==root2.val:
return self.isSubtree(root1.left,root2.left)& self.isSubtree(root1.right,root2.right)
return False
是否是平衡二叉树
题目描述
输入一棵二叉树,判断该二叉树是否是平衡二叉树。
思路:平衡二叉树的定义是任何节点的左右子树高度差都不超过1的二叉树。
按照定义,很容易得出获得左右子树高度,然后判断。递归写法。
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def IsBalanced_Solution(self, pRoot):
if not pRoot: return True
left = self.TreeDepth(pRoot.left)
right = self.TreeDepth(pRoot.right)
if abs(left - right) > 1:
return False
return self.IsBalanced_Solution(pRoot.left) and self.IsBalanced_Solution(pRoot.right)
def TreeDepth(self, pRoot):
if not pRoot: return 0
left = self.TreeDepth(pRoot.left)
right = self.TreeDepth(pRoot.right)
return max(left, right) + 1
对比:求二叉树的深度(Python代码)
def TreeDeep(self, pRoot):
if not pRoot:
return 0
left = self.TreeDeep(pRoot.left)
right = self.TreeDeep(pRoot.right)
return left+1 if left>right else right+1
!
二叉树深度和平衡二叉树
题目描述
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
链接:https://www.nowcoder.com/questionTerminal/435fb86331474282a3499955f0a41e8b
来源:牛客网
求树的深度,可以从层次遍历出发考虑
层次遍历可以使用队列完成,也可以使用递归完成,所以有两种方法
方法一:使用队列
class Solution:
# 层次遍历
def levelOrder(self, root):
# write your code here
# 存储最后层次遍历的结果
res = []
# 层数
count = 0
# 如果根节点为空,则返回空列表
if root is None:
return count
# 模拟一个队列储存节点
q = []
# 首先将根节点入队
q.append(root)
# 列表为空时,循环终止
while len(q) != 0:
# 使用列表存储同层节点
tmp = []
# 记录同层节点的个数
length = len(q)
for i in range(length):
# 将同层节点依次出队
r = q.pop(0)
if r.left is not None:
# 非空左孩子入队
q.append(r.left)
if r.right is not None:
# 非空右孩子入队
q.append(r.right)
tmp.append(r.val)
if tmp:
count += 1 # 统计层数
res.append(tmp)
return count
def TreeDepth(self, pRoot):
# write code here
# 使用层次遍历
# 当树为空直接返回0
if pRoot is None:
return 0
count = self.levelOrder(pRoot)
return count
方法二:使用递归方法
class Solution:
def TreeDepth(self, pRoot):
# write code here
# 使用层次遍历
# 当树为空直接返回0
if pRoot is None:
return 0
# 方法2:使用递归
# 如果该树只有一个结点,它的深度为1.如果根节点只有左子树没有右子树,
# 那么树的深度为左子树的深度加1;同样,如果只有右子树没有左子树,
# 那么树的深度为右子树的深度加1。如果既有左子树也有右子树,
# 那该树的深度就是左子树和右子树的最大值加1.
count = max(self.TreeDepth(pRoot.left), self.TreeDepth(pRoot.right)) + 1
return count
二叉树和为某一值的路径
题目描述
输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)
not x 意思相当于 if x is false, then True, else False
代码中经常会有变量是否为None的判断,有三种主要的写法:
第一种是if x is None;
第二种是 if not x:;
第三种是if not x is None(这句这样理解更清晰if not (x is None))
思路1:–递归
首先要理解题意,是从根节点往子节点连。
1、如果只有根节点或者找到叶子节点,我们就把其对应的val值返回
2、如果不是叶子节点,我们分别对根节点的左子树、右子树进行递归,直到找到叶子结点。然后遍历把叶子结点和父节点对应的val组成的序列返回上一层;如果没找到路径,其实也返回了序列,只不过是[]
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def FindPath(self, root,target_number):
result =[]
if not root:
return result
if not root.left and not root.right and root.val == target_number:
return [[root.val]]
else:
left = self.FindPath(root.left,target_number - root.val)
right = self.FindPath(root.right,target_number - root.val)
for item in left+right:
result.append([root.val]+item)
return result
原文:https://blog.csdn.net/zjxxyz123/article/details/79699575
思路2:和思路1类似的想法,但是提出了一些python的注意事项
这是一道DFS题目,也可以看做是先序遍历的题目 ,在二叉树中,dfs就相当于先序遍历
首先,采用一种“减法”思想,当检查一棵树从根到叶子节点形成的路径的和是否为target时,先将当前根节点的值 root.val
加入path, 然后检查它的左子树(若非空),看从左子树的根到叶子节点形成的路径的和是否为 target - root.val (递归),
然后同样的道理去递归检查右子树(若非空),这便是大致的思路。 但这道题麻烦的一点是,它要求记录下所有符合标准的路径,这便用到了dfs的特性。
但又来了一件麻烦事,先序遍历便是先左后右。检查完左子树后,会对path就行修改,再去查找右子树,如何将path恢复到之前未进行左子树检查的状态?一开始自己的做法是,每到分叉路口,到对当前路径做一份拷贝,用原路径去继续进行左子树的递归,拷贝路径进行右子树的递归,这样左子树对右子树的结果产生影响,但是这样造成了大量的拷贝,浪费空间
比较好的做法是将path设为全局的,然后dfs的过程便是先序遍历的过程,一旦遍历到叶子结点,便将path最后的节点移除掉,这样在递归一层一层进行的时候将值添加进path,在递归返回的过程中将path最末尾的元素一个一个移除。这样便依靠递归的特性完成了路径的恢复。例如对于树 10,5,12,5,7,#,#,#,#,#,#,#,#(层序遍历),path变化过程为 10,5,5 》》 10,5 》》
10,5,7 》》10,5 》》10 》》10,12 》》10 》》 null因为最终遍历到叶子结点时,若发现符合规定的路径,是把path加入到结果集中,因为java中添加的是引用,而path是不断变化的,所以我们要新new一个当前路径的副本出来,防止添加进去的path都是相同的(最终path的状态)。
当然,这道题也可以用加法的思想,看dfs过程中能否加出target
因为题意没有说节点值全为正数,所以必须递归到根节点才能确定这条路径能否加出target,而不能到中间节点就加到>=target了,就认为这条路径不行了,假如这条路径后序有0或者负数的情况,还是能加出target的。
经验教训 深刻理解DFS的用法 深刻理解递归是如何恢复path的,从先序遍历进行考虑,递归是如何一步步进行的,如何一步步返回的
最终添加入结果集中,必须添加的是path的副本 递归中,全局变量的使用
# -*- coding:utf-8 -*-
class Solution:
# 返回二维列表,内部每个列表表示找到的路径
def FindPath(self, root, expectNumber):
# write code here
if not root:
return []
ret = []
path = []
self.Find(root, expectNumber, ret, path)
# print ret
# a = [];self.f(a);print a
return ret
def Find(self, root, target, ret, path):
if not root:
return
path.append(root.val)
isLeaf = (root.left is None and root.right is None)
if isLeaf and target == root.val:
ret.append(path[:]) # 这里这一步要千万注意啊,
# 假如是:ret.append(path), 结果是错的。因为Python可变对象都是引用传递啊。
#print "target:", target, "isLeaf:", isLeaf,
#print "val:", root.val, "path:", path, "ret:", ret
#print
if root.left:
self.Find(root.left, target - root.val, ret, path)
if root.right:
self.Find(root.right, target - root.val, ret, path)
path.pop()
二叉树镜像
题目描述
操作给定的二叉树,将其变换为源二叉树的镜像。
输入描述:
二叉树的镜像定义:源二叉树
思路:
将左子树和右子树交换
递归思想,先交换根节点的左右子树的位置,然后向下递归,把左右子树的根节点作为下次循环的根节点
class Solution:
# 返回镜像树的根节点
def Mirror(self, root):
if root==None:
return
if root.left==None and root.right==None:
return
#这三步交换根节点的左右树,交换的树,而不单单是节点
tmp=root.right
root.right=root.left
root.left=tmp
if root.left is not None:
self.Mirror(root.left)
if root.right is not None:
self.Mirror(root.right)