剑指offer-Python3版(八)
从上到下打印二叉树
Q: 从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。
1
/ \
2 3
/ \
4 5
输出1,2,3,4,5
这个就是广度优先算法,bfs
思路
一般就是借助队列先进先出
把root节点加入双端队列,
先出队首个节点,加入到result,再看左右子树,有值就先加入tmp队头,(双端对列用append方法是把值放在对列头,这样下一个出队的就是左子树了,嗯,很合理)
class Deque(object):
def addFront(self, item):
self.items.append(item)
再出队加入到result,没值就跳出,
跳出之后再出队tmp的首节点…循环到tmp空,结束
class Solution:
def levelOrder(self, root) -> [int]:
if not root:
return []
# 双端队列 底层是链表,O(1),效率比单纯列表O(N)高
tmp = collections.deque()
# result 存放结果 最后return出来
result = []
tmp.append(root)
while tmp:
# popleft是collections内的方法
node = tmp.popleft()
result.append(node.val)
if node.left:
tmp.append(node.left)
if node.right:
tmp.append(node.right)
return result
二叉搜索树的后序遍历序列
Q:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。
思路
二叉搜索树的特点:对于树中的每个节点X,它的左子树中所有关键字值小于X的关键字值,而它的右子树中所有关键字值大于X的关键字值
递归分治
class Solution:
def verifyPostorder(self, postorder: [int]) -> bool:
if not postorder:
return True
def isTree(postorder):
# 根结点
root = postorder[-1]
length = len(postorder)
# 找到左子树
for i in range(length):
if postorder[i] > root:
break
# 在右子树中有比root小的,不符合
for j in range(i, length - 1):
if postorder[j] < root:
return False
left = True
if i > 0:
# 判断左子树是否符合
left = isTree(postorder[:i])
right = True
if i < length - 1:
# 判断右子树是否符合
right = isTree(postorder[i:-1])
# return right if left else left
# 如果left成立返回right
return left and right
return isTree(postorder)
二叉树中和为某一值的路径
Q:输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。
示例:
给定如下二叉树,以及目标和 sum = 22,
5
/ \
4 8
/ / \
11 13 4
/ \ / \
7 2 5 1
返回:
[
[5,4,11,2],
[5,8,4,5]
]
思路
回溯法
recur()
递推工作:
路径更新: 将当前节点值 root.val 加入路径 path ;
目标值更新: tar = tar - root.val(即目标值 tar 从 sum 减至0);
路径记录: 当 ① root 为叶节点 且 ② 路径和等于目标值 ,则将此路径 path 加入 res 。
先序遍历: 递归左 / 右子节点。
路径恢复: 向上回溯前,需要将当前节点从路径 path 中删除,即执行 path.pop() 。
class Solution:
def pathSum(self, root: TreeNode, sum: int) -> [[int]]:
# 创建2个列表 存放最终结果,以及走过的路径
res, path = [], []
def recur(root, tar):
"""
@param root:当前节点
@param tar: 当前目标值
@return: res
"""
if not root: # 空就直接返回
return
path.append(root.val)
tar -= root.val # 目标值更新
if tar == 0 and not root.left and not root.right:
# 用list(path),后序的操作不会使这里的path收到影响
# 相当于新建并复制了一个path列表
res.append(list(path))
recur(root.left, tar)
recur(root.right, tar)
# 回溯前,清空path
path.pop()
recur(root, sum)
return sum