题目来自Leetcoode,引用了一些题解和评论里面的代码翻译成了Python·。如有侵权,请联系。
二叉树的前序遍历
递归写法:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
L = []
if not root:return []
def t(node):
L.append(node.val)
if node.left:
t(node.left)
if node.right :
t(node.right)
t(root)
return L
非递归的写法:
class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
if not root:return []
stack = [root]
L = []
while(stack):
Q = stack.pop(-1)
L.append(Q.val)
if Q.right: ######注意是先right后left
stack.append(Q.right)
if Q.left:
stack.append(Q.left)
return L
# 另外一种
if not root:return []
s = []
ans = []
node = root
while(node or s):
while(node):
ans.append(node.val) # 存根节点
s.append(node) # 为了判断右子树
node = node.left # 直到最左子树
node = s[-1].right # 最左子树的右子树
s.pop()
return ans
注意利用栈去存节点的时候,先right后left。因为栈是先进后出的,如果[left,right] => pop() => [right,left]所以要先存right。
二叉树的中序遍历
递归版本
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
if not root:return []
L = []
def t(node):
if node.left:
t(node.left)
L.append(node.val)
if node.right:
t(node.right)
t(root)
return L
# 中序遍历 先遍历左子树->根节点->右子树
# 如果是递归做法则递归遍历左子树,访问根节点,递归遍历右子树
# 非递归过程即:先访问..最左子树..结点,再访问其父节点,再访问其兄弟
# while循环条件 中序遍历需先判断当前结点是否存在,若存在则将该节点放入栈中,再将当前结点设置为结点的左孩子,
# 若不存在则取栈顶元素[最左节点]为cur,在访问cur的右节点。
# 当且仅当栈空cur也为空,循环结束。
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
if not root:return []
s = []
v = []
node = root
while(node or s):
if node :
s.append(node)
node = node.left
else:
node = s.pop(-1) # 最后一个
v.append(node.val)
node = node.right
return v
二叉树的后序遍历
递归版本
class Solution:
def postorderTraversal(self, root: TreeNode) -> List[int]:
if not root:return []
L = []
def t(node):
if node.left:
t(node.left)
if node.right:
t(node.right)
L.append(node.val)
t(root)
return L
非递归版本
(1)输出层次遍历的逆
class Solution(object):
def postorderTraversal(self, root):
# 层次遍历从左到右,从上到下 -> 队列
# 深度遍历从左到右,从下到上 -> 栈
# 栈:根->左->右
# output:根->右->左 层次不会变
# output[::-1]:左->右->根
if root is None:
return []
stack, output = [root, ], []
while stack:
print([node.val for node in stack])
root = stack.pop()
output.append(root.val)
if root.left is not None:
stack.append(root.left)
if root.right is not None:
stack.append(root.right)
return output[::-1]
(2)利用pre判断右节点是否被输出,从左到右的去遍历。来自此处。
if not root: return []
s,v = [],[]
cur = root
pre = None
while(cur or s):
while(cur):
s.append(cur)
cur=cur.left ##遍历左子树
cur = s[-1]
if cur.right == None or cur.right == pre: #判断是否该输出结点
v.append(cur.val)
s.pop()
pre = cur
cur = None
else:
cur=cur.right
return v
二叉树的层次遍历
(1)107. 二叉树的层次遍历 II (2)199. 二叉树的右视图
if not root:return []
q = [root]
L = []
while(q):
node=q.pop(0) #队列,先进先出
L.append(node.val)
if node.left:
q.append(node.left)
if node.right:
q.append(node.right)
return L
二叉树的深度 统计
(1)面试题55 - I. 二叉树的深度 (2) 104. 二叉树的最大深度 (3) 剑指 Offer 55 - II. 平衡二叉树
递归
class Solution:
def maxDepth(self, root: TreeNode) -> int:
def t(root): O(N) O(N)
if not root:
return 0
left = t(root.left)+1
right = t(root.right)+1
return left if left>right else right
depth = t(root)
return depth
def depth(root): ## 第二种不同方式的
if not root:return 0
return max(depth(root.left),depth(root.right))+1
return depth(root)
非递归(层次遍历的层数)
class Solution:
def maxDepth(self, root: TreeNode) -> int:
# 层次遍历的层数 O(N) O(N)
if not root:return 0
q = [root]
ans = 0
while(q):
ans +=1
size = len(q)
for i in range(0,size):
node = q.pop(0)
if node.left:
q.append(node.left)
if node.right:
q.append(node.right)
return ans
(3)平衡二叉树
解决方法1:计算每棵树的左右子树高度差,当每一层都满足平衡二叉树时,返回Ture,否则返回False
时间复杂度分析:最坏情况是“满二叉树”时,那么每层节点访问 O(logN)。每一层的每个节点都要进行一次深度计算,那么第一层是 N*1,(N-1)/2 *2,...,1*N。最坏的情况就是要调用N次depth函数。故最终时间复杂度是O(NlogN)。补完全二叉树。
空间复杂度:O(N),最坏退化到链表,系统需要使用O(N)的栈空间。
class Solution:
def isBalanced(self, root: TreeNode) -> bool:
def find_depth(root):
if not root:return 0 ## 深度 返回深度
left = find_depth(root.left)+1
right = find_depth(root.right)+1
return left if left>right else right
def judge(root):
if not root:return True ## 判断真假 ,return True or False
left = find_depth(root.left)
right = find_depth(root.right)
if abs(left-right)>1:
return False
return judge(root.left) and judge(root.right) ## 左右都要平衡
return judge(root)
解法二:利用后序遍历+剪枝。题解链接。
def judge(root):
if not root:return 0
left = judge(root.left) # 先找左子树
if left == -1:return -1 ## 体现剪枝
right = judge(root.right) # 找右子树
if right == -1:return -1
return max(left,right)+1 if abs(left-right)<=1 else -1 ## 根节点情况
return judge(root) != -1
二叉树的单条路径
输出二叉树的中的每条路径。例子:
class Solution:
def pathSum(self, root: TreeNode, sum_: int) -> List[List[int]]:
# DFS,找出所有路径
L = []
def find_all_path(root,path):
if not root:return
path.append(root.val)
if not root.left or not root.right :
L.append(path.copy())
## 深浅拷贝问题,如果不利用copy(),那么path改变L中的path也会改变
find_all_path(root.left,path)
find_all_path(root.right,path)
path.pop()
## 回溯点,当递归到 node(7)时,find_all_path(left,right)均return,
## 此时 path = [5,4,11,7] 向上回溯时,将7删掉,否则 node(2)分支,return[5,4,11,7,2]
find_all_path(root,[])
return L
output:[[5,4],[5,4,11,7],[5,4,11,2],[5,8,13],[5,8,4,5],[5,8,4,1]]
与其相关的题目 剑指 Offer 34. 二叉树中和为某一值的路
上面这个题,可以用于筛选所有分支。可以在上面代码的基础上,添加:
ans = []
for nums in L :
if sum(nums) == sum_:
ans.append(nums)
return ans
也可以将sum_加在DFS里面。两篇比较好的解释:链接1,链接2.(下面代码参考了链接2)
class Solution:
def pathSum(self, root: TreeNode, sum_: int) -> List[List[int]]:
# DFS,找出所有路径
L = []
def find_all_path(root,path,sum_):
if not root:return
path.append(root.val)
if sum_ == root.val and not root.left and not root.right :
L.append(path.copy()) ## 深浅拷贝问题
find_all_path(root.left,path,sum_-root.val) ## 每次都把root.val的值减掉
find_all_path(root.right,path,sum_-root.val)
path.pop() ## 回溯点
find_all_path(root,[],sum_)
return L