程序员代码面试指南 python实现(第三章:二叉树问题)
- 程序员代码面试指南 python实现(第三章:二叉树问题)
- 分别用递归和非递归方式实现二叉树先序、中序和后序遍历
- 打印二叉树的边界节点
- 如何较为直观地打印二叉树
- 二叉树的序列化和反序列化
- 遍历二叉树的神级方法
- 在二叉树中找到累加和为指定值的最长路径长度
- 找到二叉树中的最大搜索二叉树子树
- 二叉树的按层打印与ZigZag打印
- 调整搜索二叉树中两个错误的节点
- 判断t1树是否包含t2树全部的拓扑结构
- 判读t1树中是否有与t2树拓扑结构完全的子树
- 判断二叉树是否为平衡二叉树
- 根据后序数组重建搜索二叉树
- 判断一棵树是否为搜索二叉树和完全二叉树
- 通过有序数组生成平衡搜索二叉树
- 在二叉树中找到一个节点的后继节点
- 在二叉树中找到两个节点的最近公共祖先
- 再进阶:Tarjan算法与并查集解决二叉树节点间最近公共祖先的批量查询问题
- 二叉树节点间的最大距离问题
- 先序、中序和后序数组两两结合重构二叉树
- 通过先序和中序数组生成后序数组
- 统计和生成不同的二叉树
- 统计完全二叉树的节点数
程序员代码面试指南 python实现(第三章:二叉树问题)
分别用递归和非递归方式实现二叉树先序、中序和后序遍历
二叉树先序遍历
递归
def preOrderRecur(self,head):
if head == None:
return
print(str(head.val)+" ")
self.preOrderRecur(head.left)
self.preOrderRecur(head.right)
非递归
def preOrderUnRecur(self,head):
if head != None:
stack = []
stack.append(head)
while len(stack) != 0:
head = stack.pop()
print(str+" ")
if head.right != None:
stack.append(head.rigth)
if head.left != None:
stack.append(head.left)
二叉树中序遍历
递归
def inOrderRecur(self,head):
if head == None:
return
self.inOrderRecur(head.left)
print(str(head.val)+" ")
self.inOrderRecur(head.right)
非递归
def inOrderUnRecur(self,head):
if head != None:
stack = []
while len(stack) != 0 or head != None:
if head != None:
stack.append(head)
head = head.left
else:
head = stack.pop()
print(str(head.val)+" ")
head = head.right
二叉树后序遍历
递归
def posOrderRecur(self,head):
if head == None:
return
self.posOrderRecur(head.left)
self.posOrderRecur(head.right)
print(str(head.val)+" ")
非递归
两个栈
def posOrderUnRecur1(self,head)
if head != None:
s1 = []
s2 = []
s1.append(head)
while len(s1) != 0:
head = s1.pop()
s2.append(head)
if head.left != None:
s1.appned(head.left)
if head.right != None:
s1.append(head.right)
while len(s2) != 0:
print(str(s2.pop().val) + " ")
一个栈
def posOrderUnRecur2(self,head):
if head != None:
stack = []
stack.append(head)
while len(stack) != 0:
c = stack[-1]
if c.left != None and head != c.left and head != c.right:
stack.append(c.left)
elif c.right != None and head != c.right:
stack.append(c.right)
else:
print(str(stack.pop().val)+" ")
head = c
打印二叉树的边界节点
标准一
class TreeNode(object):
def __init__(self,x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def printEdge1(self,head):
if head == None:
return
height = self.getHeght(head,0)
edgeMap = [[-1]*2]*height
self.setEdgeMap(head,0,edgeMap)
# 打印左边界
for i in range(0,len(edgeMap)):
print(edgeMap[i][0].val + " ")
# 打印非边界的叶子节点
self.printLeafNotInMap(head,0,edgeMap)
#打印右边界
for i in range(len(edgeMap)-1,-1,-1):
if edgeMap[i][0] != edgeMap[i][1]:
print(edgeMap[i][1].val + " ")
def getHeght(self,head,l):
if head == None:
return l
return max(self.getHeght(head.left,l+1),self.getHeght(head.right,l+1))
def setEdgeMap(self,head,l,edgeMap):
if head == None:
return
edgeMap[1][0] = head if edgeMap[1][0] == None else edgeMap[1][0]
edgeMap[1][1] = head
self.setEdgeMap(head.left,l+1,edgeMap)
self.setEdgeMap(head.right,l+1,edgeMap)
def printLeafNotInMap(self,head,l,m):
if head == None:
return
if head.left == None and head.right == None and head != m[1][0] and head != m[l][l]:
print(head.val + " ")
self.printLeafNotInMap(head.left,l+1,m)
self.printLeafNotInMap(head.right,l+1,m)
标准二
如何较为直观地打印二叉树
二叉树的序列化和反序列化
通过先序遍历
序列化
def serialByPre(self,head):
if head == None:
return "#!"
res = head.val + "!"
res += self.serialByPre(head.left)
res += self.serialByPre(head.right)
return res
反序列化
def reconByPreString(self,preStr):
values = preStr.split("!")
queue = []
for i in range(0,len(values)):
queue.append(values[i])
return self.reconPreOrder(queue)
def reconPreOrder(self,queue):
value = queue.pop(0)
if value == "#":
return None
head = TreeNode(int(value))
head.left = self.reconPreOrder(queue)
head.right = self.reconPreOrder(queue)
return head
通过层遍历实现
序列化
def serialByLevel(self,head):
if head == None:
return "#!"
res = head.val + "!"
queue = []
queue.append(head)
while len(queue) != 0:
head = queue.pop(0)
if head.left != None:
res += head.left.val + "!"
queue.append(head.left)
else:
res += "#!"
if head.right != None:
res += head.right.val + "!"
queue.append(head.right)
else:
res += "#!"
return res
反序列化
def reconByLevelString(self,levelStr):
values = levelStr.split("!")
index = 0
head = self.generateNodeByString(values[index])
index += 1
queue = []
if head != None:
queue.append(head)
while len(queue) != 0:
node = queue.pop(0)
node.left = self.generateNodeByString(values[index])
index += 1
node.right = self.generateNodeByString(values[index])
index += 1
if node.left != None:
queue.append(node.left)
if node.right != None:
queue.append(node.right)
return head
def generateNodeByString(self,val):
if val == "#":
return None
return TreeNode(int(val))
遍历二叉树的神级方法
在二叉树中找到累加和为指定值的最长路径长度
class TreeNode(object):
def __init__(self,x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def getMaxLength(self,head,sum):
sumMap = {}
sumMap[0] = 0
return self.preOrder(head,sum,0,1,0,sumMap)
def preOrder(self,head,sum,preSum,level,maxLen,sumMap):
if head == None:
return maxLen
curSum = preSum + head.val
if curSum not in sumMap.keys():
sumMap[curSum]=level
if (curSum-sum) in sumMap.keys():
maxLen = max(level-sumMap[(curSum-sum)],maxLen)
maxLen = self.preOrder(head.left,sum,curSum,level+1,maxLen,sumMap)
maxLen = self.preOrder(head.right,sum,curSum,level+1,maxLen,sumMap)
if level == sumMap[curSum]:
sumMap.pop(curSum)
return maxLen
if __name__ == "__main__":
node1 = TreeNode(-3)
node2 = TreeNode(3)
node3 = TreeNode(-9)
node4 = TreeNode(1)
node5 = TreeNode(0)
node6 = TreeNode(2)
node7 = TreeNode(1)
node8 = TreeNode(1)
node9 = TreeNode(6)
node1.left = node2
node1.right = node3
node2.left = node4
node2.right = node5
node3.left = node6
node3.right = node7
node5.left = node8
node5.right = node9
solu = Solution()
print(solu.getMaxLength(node1,6))
找到二叉树中的最大搜索二叉树子树
class Node(object):
def __init__(self,x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def biggestSubBST(self,head):
record = [-1]*3
return self.posOrder(head,record)
def posOrder(self,head,record):
if head == None:
record[0] = 0
record[1] = float('inf')
record[2] = float('-inf')
return None
value = head.val
left = head.left
right = head.right
leftBST = self.posOrder(left,record)
leftSize = record[0]
leftMin = record[1]
leftMax = record[2]
rightBST = self.posOrder(right,record)
rightSize = record[0]
rightMin = record[1]
rightMax = record[2]
record[1] = min(leftMin,value)
record[2] = max(rightMax,value)
if left == leftBST and right == rightBST and leftMin < value and value < rightMin:
record[0] = leftSize + rightSize + 1
return head
record[0] = max(leftSize,rightSize)
return leftBST if leftSize > rightSize else rightBST
二叉树的按层打印与ZigZag打印
按层次打印
def printByLevel(self,head):
if head == None:
return
queue = []
level = 1
last = head
nLast = None
queue.append(head)
print("Level "+ str(level)+" : ")
level += 1
while len(queue) != 0:
head = queue.pop(0)
print(str(head.val)+" ")
if head.left != None:
queue.append(head.left)
nLast = head.left
if head.right != None:
queue.append(head.right)
nLast = head.right
if head == last and len(queue) != 0:
print("Level "+ str(level) + " : ")
level += 1
last = nLast
ZigZag打印
def printByZigzag(self,head):
if head == None:
return
dq = collections.deque()
level = 1
lr = True
last = head
nLast = None
dq.appendleft(head)
self.pringLevelAndOrientation(level,lr)
level += 1
while len(dq) != 0:
if lr:
head = dq.popleft()
if head.left != None:
nLast = head.left if nLast == None else nLast
dq.append(head.left)
if head.right != None:
nLast = head.right if nLast == None else nLast
dq.append(head.right)
else:
head = dq.pop()
if head.right != None:
nLast = head.right if nLast == None else nLast
dq.appendleft(head.right)
if head.left != None:
nLast = head.left if nLast == None else nLast
dq.appendleft(head.left)
print(str(head.val)+" ")
if head == last and len(dq) != 0:
lr = not lr
last = nLast
nLast = None
print(" ")
self.pringLevelAndOrientation(level,lr)
level += 1
def pringLevelAndOrientation(self,level,lr):
print("Level "+ str(level) + " from ")
if lr:
print("left to right:")
else:
print("right to left")
调整搜索二叉树中两个错误的节点
判断t1树是否包含t2树全部的拓扑结构
class TreeNode(object):
def __init__(self,x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def contains(self,t1,t2):
return self.check(t1,t2) or self.check(t1.left,t2) or self.check(t1.right,t2)
def check(self,h,t2):
if t2 == None:
return True
if h == None or h.val != t2.val:
return False
return self.check(h.left,t2.left) and self.check(h.right,t2.right)
判读t1树中是否有与t2树拓扑结构完全的子树
在这里插入代码片
判断二叉树是否为平衡二叉树
solution(object):
def isBalance(self,head):
res = True
self.getHeight(head,1,res)
return res
def getHeight(self,head,level,res):
if head == None:
return level
leftH = self.getHeight(head.left,level + 1,res)
if not res:
return level
rightH = self.getHeight(head.right,level+1,res)
if not res:
return level
if abs(leftH-rightH) > 1:
res =False
return max(leftH,rightH)
根据后序数组重建搜索二叉树
原问题
solution(object):
def isPostArray(self,arr):
if arr == None or len(arr) == 0:
return False
return self.isPost(arr,0,len(arr)-1)
def isPost(self,arr,start,end):
if start == end:
return True
less = -1
more = end
for i in range(start,end):
if arr[end] > arr[i]:
less = i
else:
more = i if more == end else more
if less == -1 or more == end:
return self.isPost(arr,start,end-1)
if less != more - 1:
return False
return self.isPost(arr,start,less) and self.isPost(arr,more,end-1)
进阶
class Solution2(object):
def posArrayToBST(self,posArr):
if posArr == None:
return None
return self.posToBST(posArr,0,len(posArr)-1)
def posToBST(self,posArr,start,end):
if start > end:
return None
head = Node(posArr[end])
less = -1
more = end
for i in range(start,end):
if posArr[end] > posArr[i]:
less = i
else:
more = i if more == end else more
head.left = self.posToBST(posArr,start,less)
head.right = self.posToBST(posArr,more,end-1)
return head
判断一棵树是否为搜索二叉树和完全二叉树
判断搜索二叉树
class TreeNode(object):
def __init__(self,x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def isBST(self,head):
if head == None:
return True
res = True
pre = None
cur1 = head
cur2 = None
while cur1 != None:
cur2 = cur1.left
if cur2 != None:
while cur2.right != None and cur2.right != cur1:
cur2 = cur2.right
if cur2.right == None:
cur2.right = cur1
cur1 = cur1.left
continue
else:
cur2.right = None
if pre != None and pre.val > cur1.val:
res = False
pre = cur1
cur1 = cur1.right
return res
判断完全二叉树
def isCBT(self,head):
if head == None:
return True
queue = []
leaf = False
l = None
r = None
queue.append(head)
while len(queue) != 0:
head = queue.pop(0)
l = head.left
r = head.right
if leaf and (l != None or r != None) or (l == None and r != None):
return False
if l != None:
queue.append(l)
if r != None:
queue.append(r)
else:
leaf = True
return True
通过有序数组生成平衡搜索二叉树
class TreeNode(object):
def __init__(self,x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def generateTree(self,sortArr):
if sortArr == None:
return None
return self.generate(sortArr,0,len(sortArr)-1)
def generate(self,sortArr,start,end):
if sortArr == None:
return None
mid = (start+end)//2
head = TreeNode(sortArr[mid])
head.left = self.generate(sortArr,start,mid - 1)
head.right = self.generate(sortArr,mid+1,end)
return head
在二叉树中找到一个节点的后继节点
class TreeNode(object):
def __init__(self,x):
self.val = x
self.left = None
self.right = None
self.parent = None
class Solution(object):
def getNextNode(self,node):
if node == None:
return node
if node.right != None:
return self.getLeftMost(node.right)
else:
parent = node.parent
while parent != None and parent != node:
node = parent
parent = node.parent
return parent
def getLeftMost(self,node):
if node == None:
return None
while node.left != None:
node = node.left
return node
在二叉树中找到两个节点的最近公共祖先
原问题
class TreeNode(object):
def __init__(self,x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def lowestAncestor(self,head,o1,o2):
if head == None or head == o1 or hed == o2:
return head
left = self.lowestAncestor(head.left,o1,o2)
right = self.lowestAncestor(head.right,o1,o2)
if left != None and right != None:
return head
if left != None:
return left
else:
return right
if __name__ == "__main__":
node1 = TreeNode(1)
node2 = TreeNode(2)
node3 = TreeNode(3)
node4 = TreeNode(4)
node5 = TreeNode(5)
node6 = TreeNode(6)
node7 = TreeNode(7)
node8 = TreeNode(8)
node1.left = node2
node1.right = node3
node2.left = node4
node2.right = node5
node3.left = node6
node3.right = node7
node7.left = node8
solu = Solution()
print(solu.lowestAncestor(node1,node6,node8).val)
进阶
在这里插入代码片
再进阶:Tarjan算法与并查集解决二叉树节点间最近公共祖先的批量查询问题
二叉树节点间的最大距离问题
class TreeNode(object):
def __init__(self,x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def maxDistance(self,head):
record = 0
return self.posOrder(head,record)
def posOrder(self,head,record):
if head == None:
record = 0
return 0
leftMax = self.posOrder(head.left,record)
maxfromLeft = record
rightMax = self.posOrder(head.right,record)
maxfromRight = record
curNodeMax = maxfromLeft + maxfromRight + 1
record = max(maxfromLeft,maxfromRight) + 1
return max(max(leftMax,rightMax),curNodeMax)
if __name__ == "__main__":
solu = Solution()
node1 = TreeNode(1)
node2 = TreeNode(2)
node3 = TreeNode(3)
node4 = TreeNode(4)
node5 = TreeNode(5)
node6 = TreeNode(6)
node7 = TreeNode(7)
node1.left = node2
node1.right = node3
node2.left = node4
node2.right = node5
node3.left = node6
node3.right = node7
print(solu.maxDistance(node1))
先序、中序和后序数组两两结合重构二叉树
先序与中序结合
class Solution(object):
# 前序和中序
def preInToTree(self,preOrder,inOrder):
if preOrder == None or inOrder == None:
return None
dict = {}
for i in range(0,len(inOrder)):
dict[inOrder[i]] = i
return self.preIn(preOrder,0,len(preOrder)-1,inOrder,0,len(inOrder)-1,dict)
def preIn(self,p,pi,pj,n,ni,nj,dict):
if pi > pj:
return None
head = TreeNode(p[pi])
index = dict[p[pi]]
head.left = self.preIn(p,pi+1,pi+index-ni,n,ni,index-1,dict)
head.right = self.preIn(p,pi+index-ni+1,pj,n,index+1,nj,dict)
return head
中序与后续结合
# 中序和后序
def inPosTOTree(self,inOrder,posOrder):
if inOrder == None or posOrder == None:
return None
dict = {}
for i in range(0,len(inOrder)):
dict[inOrder[i]] = i
return self.inPos(inOrder,0,len(inOrder)-1,posOrder,0,len(posOrder),dict)
def inPos(self,n,ni,nj,s,si,sj,dict):
if si > sj:
return None
head = TreeNode(s[sj])
index = dict[s[sj]]
head.left = self.inPos(n,ni,index-1,s,si,si+index-ni-1,dict)
head.right = self.inPos(n,index+1,nj,s,si+index-ni,sj-1,dict)
return head
先序与后续结合
#前序和后序
def prePosToTree(self,preOrder,posOrder):
if preOrder == None or posOrder == None:
return None
dict = {}
for i in range(0,len(posOrder)):
dict[posOrder[i]] = i
return self.prePos(preOrder,0,len(preOrder)-1,posOrder,0,len(posOrder)-1,dict)
def prePos(self,p,pi,pj,s,si,sj,dict):
head = TreeNode(s[sj])
sj -= 1
if pi == pj:
return head
pi += 1
index = dict[p[pi]]
head.left = self.prePos(p,pi,pi+index-si,s,si,index,dict)
head.right = self.prePos(p,pi+index-si+1,pj,s,index+1,sj,dict)
return head
通过先序和中序数组生成后序数组
class TreeNode(object):
def __init__(self,x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def getPosArray(self,preOrder,inOrder):
if preOrder == None or inOrder == None:
return None
len = len(preOrder)
pos = [-1]*len
dict = {}
for i in range(0,len):
dict[inOrder[i]] = i
self.setPos(preOrder,0,len-1,inOrder,0,len-1,pos,len-1,dict)
return pos
def setPos(self,p,pi,pj,n,ni,nj,s,si,dict):
if pi > pj:
return si
s[si] = p[pi]
i = dict[p[pi]]
si = self.setPos(p,pj-nj+i+1,pj,n,i+1,nj,s,si,dict)
return self.setPos(p,pi+1,pi+i-ni,n,ni,i-1,s,si,dict)
统计和生成不同的二叉树
统计
动态规划
class TreeNode(object):
def __init__(self,x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def numTrees(self,n):
if n < 2:
return 1
num = [None]*(n+1)
num[0] = 1
for i in range(1,n+1):
for j in range(1,i+1):
num[i] += num[j-1]*num[i-j]
return num[n]
生成
def generate(self,start,end):
res = []
if start > end:
res.append(None)
head = None
for i in range(start,end+1):
head = TreeNode(i)
lSubs = self.generate(start,i-1)
rSubs = self.generate(i+1,end)
for l in lSubs:
for r in rSubs:
head.left = l
head.right = r
res.append(self.cloneTree(head))
return res
def cloneTree(self,head):
if head == None:
return None
res = TreeNode(head.val)
res.left = self.cloneTree(head.left)
res.right = self.cloneTree(head.right)
return res
统计完全二叉树的节点数
class TreeNode(object):
def __init__(self,x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def nodeNum(self,head):
if head == None:
return 0
return self.bs(head,1,self.mostLeftLevel(head,1))
def bs(self,node,l,h):
if l == h:
return l
if self.mostLeftLevel(node.right,l+1) == h:
return (1 << (h-1)) + self.bs(node.right,l+1,h)
else:
return (1 << (h-l-1)) + self.bs(node.left,l+1,h)
def mostLeftLevel(self,node,level):
while node != None:
level += 1
node = node.left
return level - 1