所有例题的编程语言为python
二叉树节点结构:
class TreeNode(object):
def __init__(self, x):
self.val = x
self.left = None
self.right = None
inorder=[9,3,15,20,7] 左根右
postorder=[9,15,7,20,3] 左右根,逆序就是根右左:[3,20,7,15,9]
由后序遍历中可知根节点是3,在中序遍历中可以确定左右子树序列是多少。如何提取下一个根节点呢?取根和左右子树递归构造该如何衔接。
inorder 用来控制递归出口
postorder 才是提供根节点的源泉。
class Solution(object):
def buildTree(self, inorder, postorder):
"""
:type inorder: List[int]
:type postorder: List[int]
:rtype: TreeNode
"""
global pos_index
postorder.reverse()
def helper(in_left=0,in_right=len(inorder)):
global pos_index
if in_left==in_right:
return None
root_val=postorder[pos_index]
root=TreeNode(root_val)
pos_index+=1
in_index=inorder.index(root_val)
root.right=helper(in_index+1,in_right)
root.left=helper(in_left,in_index)
return root
pos_index=0
return helper()
preorder=[3,9,20,15,7] 中左右
inorder=[9,3,15,20,7] 左中右
一个根节点可以将中序遍历划分为左一半,右一半。
全局变量pre_idx,每次运行一次helper函数一次加1,取下一根节点;直至左子树运行完,对应的根节点下标也应该遍历完全了。
剩余问题:index不因该是根节点的在中序遍历中的下标么?左子树包含的内容不是应该为[0,index-1] 根递归出口有关,不是直接索引元素。
class Solution(object):
def buildTree(self, preorder, inorder):
"""
:type preorder: List[int]
:type inorder: List[int]
:rtype: TreeNode
"""
global pre_index
def helper(in_left=0,in_right=len(inorder)):
global pre_index
if in_left==in_right:
return None
root_val=preorder[pre_index]
root=TreeNode(root_val)
pre_index+=1
in_index=inorder.index(root_val)
root.left=helper(in_left,in_index)
root.right=helper(in_index+1,in_right)
return root
pre_index=0
return helper()
填充一个完美二叉树的每个解答的每个节点的下一个右侧节点。完美二叉树说的是,所有叶子节点都在同一层。
思路:关键找到每一个节点的下一个节点,那不就是二叉树的层次遍历。
每层的节点的next指针指其下一个节点,用l来控制该层的最后一个节点指向None。
class Solution(object):
def connect(self, root):
"""
:type root: Node
:rtype: Node
"""
if root==None:
return None
que=[root]
while(que):
l=len(que)
for i in range(l):
node=que.pop(0)
if i==l-1:
node.next=None
else:
node.next=que[0]
if node.left:
que.append(node.left)
if node.right:
que.append(node.right)
return root
给定一个二叉树,填充它每个next指针指向右侧节点,同一层的最右侧节点填充为None.
思路:不是一棵完美的二叉树,不过还是树的层次遍历,上一题的框架依旧可以使用。
代码一点没改能过。
给定一个二叉树,找到该树中两个指定节点的最近公共祖先。
官方思路1:递归
递归遍历整棵树,定义 f x f_x fx表示x节点的子树中是否包含p节点或者q节点,如果包含则为true.采用自底向上从叶子节点开始更新,保证满足条件的公共祖先深度最深。
class Solution(object):
def __init__(self):
self.ans=None
def lowestCommonAncestor(self, root, p, q):
def rec(node,p,q):
if node==None:
return False
left=rec(node.left,p,q) # 记录左子树的有没有待识别的点
right=rec(node.right,p,q) # 记录右子树有没有待识别的点
mid=(node==p or node==q)
if mid+left+right==2:
self.ans=node
return mid or left or right
rec(root,p,q)
return self.ans
官方思路2:储存父节点
用hash表存储所有节点的父亲节点,然后利用节点的父亲节点的信息从p往上跳,直至根节点,记录已经访问过的节点;再从q节点开始不断往上跳,每次上跳一个节点就去p已访问的节点中寻找是否已经访问过该节点。第一次遇到的p已经访问的节点,则该节点为答案。
难点1:父亲节点hash表。{child1:root1,child2:root1},只要遍历过二叉树的所有节点,就可以实现这个。
难点2:从p开始,不断在父亲hash表中找父亲节点,直至找不到父亲节点的跟节点,将所有路径放入[]中。
技巧:还是将节点放进去。
class Solution(object):
def lowestCommonAncestor(self, root, p, q):
"""
:type root: TreeNode
:type p: TreeNode
:type q: TreeNode
:rtype: TreeNode
"""
def dfs(node):
if node==None:
return
if node.left:
fa_hash[node.left]=node
if node.right:
fa_hash[node.right]=node
dfs(node.left)
dfs(node.right)
fa_hash={root:None}
vis_hash={}
dfs(root)
while (p!=None):
# print(p)
vis_hash[p]=True # 要记得把自己放进去
p=fa_hash[p]
while(q!=None):
if vis_hash.get(q): # 记得自己也要验证
return q
q=fa_hash[q]
将二叉树序列化为一个字符串,将得到的字符串反序列化为二叉树。
说明:不要使用类成员/全局/静态变量来存储状态,序列化和反序列化算法应该是无状态的。–什么是无状态?
序列化和反序列化递归顺序一致就可以。
class Codec:
def serialize(self, root):
"""Encodes a tree to a single string.
:type root: TreeNode
:rtype: str
"""
def dfs_ser(node,string):
if node==None:
string+="None,"
return string
string+="{0},".format(node.val)
string=dfs_ser(node.left,string)
string=dfs_ser(node.right,string)
return string
return dfs_ser(root,"")
def deserialize(self, data):
"""Decodes your encoded data to tree.
:type data: str
:rtype: TreeNode
"""
def rec_deser(lis):
if lis[0]=="None":
lis.pop(0)
return None
root_val=lis[0]
root=TreeNode(root_val) # 顶端
lis.pop(0)
root.left=rec_deser(lis) # 底端
root.right=rec_deser(lis)
return root
lis=data.split(",")
return rec_deser(lis)