2.白银挑战——二叉树的层次遍历经典问题
2.基本的层次遍历与变换
2.1 二叉树的层序遍历
LeetCode102:给你一个二叉树,请你返回其按层序遍历得到的节点值。(即逐层地,从左到右访问所有节点)。
按层打印经典代码:
class Node:
def __init__(self, val=-1, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Tree:
def __init__(self, root=None):
self.root = root
def init_tree(self):
node_9 = Node(9)
node_15 = Node(15)
node_7 = Node(7)
node_20 = Node(20, node_15, node_7)
root = Node(3, node_9, node_20)
return root
class LevelOrder:
def basic_level_order(self, root):
if not root:
return []
res = []
queue = [root]
while queue:
size = len(queue)
tmp = []
# 将队列中元素都拿出来,放在临时List中
for _ in range(size):
r = queue.pop(0)
tmp.append(r.val)
if r.left:
queue.append(r.left)
if r.right:
queue.append(r.right)
res.append(tmp)
return res
if __name__ == "__main__":
tree = Tree()
root = tree.init_tree()
levelOrder = LevelOrder()
res = levelOrder.basic_level_order(root)
print(res)
2.2 层次遍历——自底向上
思路:在遍历完一层节点之后,将存储该层节点值的列表添加到结果列表的头部
import collections
class Node:
def __init__(self, val=-1, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Tree:
def __init__(self, root=None):
self.root = root
def init_tree(self):
node_9 = Node(9)
node_15 = Node(15)
node_7 = Node(7)
node_20 = Node(20, node_15, node_7)
root = Node(3, node_9, node_20)
return root
class LevelOrderBottom:
def levelOrderBottom(self, root):
levelOrder = list()
if not root:
return levelOrder
q = collections.deque([root])
while q:
level = list()
size = len(q)
for _ in range(size):
node = q.popleft()
level.append(node.val)
if node.left:
q.append(node.left)
if node.right:
q.append(node.right)
levelOrder.append(level)
return levelOrder[::-1]
if __name__ == "__main__":
tree = Tree()
root = tree.init_tree()
levelOrder = LevelOrderBottom()
res = levelOrder.levelOrderBottom(root)
print(res)
deque() (双向队列)
deque是栈和队列的一种广义实现,deque是"double-end queue"的简称;deque支持线程安全、有效内存地以近似O(1)的性能在deque的两端插入和删除元素,尽管list也支持相似的操作,但是它主要在固定长度操作上的优化,从而在pop(0)和insert(0,v)(会改变数据的位置和大小)上有O(n)的时间复杂度。
常用方法:
append():从右端添加元素,
appendleft():从左端添加元素,
extend():从右端逐个添加可迭代对象,
python中的可迭代对象有:列表,元组,字典,字符串,
extendleft():从左端逐个添加可迭代对象,
pop():移除列表中的一个元素(默认最右端的一个元素)并返回该元素的值,如果没有元素,将会报出IndexError
popleft():移除列表中的一个元素(默认最左端的一个元素),并且返回该元素的值,如果没有元素,将会报出IndexError
count():统计队列中的元素个数
insert(index,obj):在指定位置插入元素
rotate(n):rotate(n), 从右侧反转n步,如果n为负数,则从左侧反转。d.rotate(1) 等于 d.appendleft(d.pop())
clear():将deque中的元素全部删除,最后长度为0
remove():移除第一次出现的元素,如果没有找到,报出ValueError
maxlen:只读的属性,deque限定的最大长度,如果无,就返回None。当限制长度的deque增加超过限制数的项时, 另一边的项会自动删除
2.3二叉树的锯齿形层序遍历
LeetCode103:给定一个二叉树,返回其节点值的锯齿形层序遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。
如果是从左至右,我们每次将被遍历到的元素插入至双端队列的末尾
从右至左,我们每次将被遍历到的元素插入至双端队列的头部。
import collections
class Node:
def __init__(self, val=-1, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Tree:
def __init__(self, root=None):
self.root = root
def init_tree(self):
node_9 = Node(9)
node_15 = Node(15)
node_7 = Node(7)
node_20 = Node(20, node_15, node_7)
root = Node(3, node_9, node_20)
return root
class ZigzagLevelOrder:
def zigzagLevelOrder(self, root):
if not root:
return []
res = []
q = collections.deque() #q为一个双端可插入的序列
q.append(root)
while q:
res_tmp = []
n = len(q)
for i in range(n):
tmp = q.popleft()
res_tmp.append(tmp.val)
if tmp.left:
q.append(tmp.left)
if tmp.right:
q.append(tmp.right)
res.append(res_tmp)
for j in range(len(res)):
if j % 2 == 1:
res[j].reverse()
return res # return的位置
if __name__ == '__main__':
tree = Tree()
root = tree.init_tree()
zigzag = ZigzagLevelOrder()
res = zigzag.zigzagLevelOrder(root)
print(res)
2.4 N叉树的层序遍历
LeetCode429:给定一个N叉树,返回其节点值的层序遍历。(即从左到右,逐层遍历)
树的序列化输入是用层序遍历,每组节点都有null值分隔
class NLevelOrder:
def nlevelOrder(self, root: 'Node'):
if not root:
return []
ans = list()
q = deque([root])
while q:
n = len(q)
level = list()
for _ in range(n):
cur = q.popleft()
level.append(cur.val)
for child in range(len(level)):
q.append(child)
ans.append(level)
return ans
3.几个处理每层元素的题目
3.1在每个树行中找最大值
LeetCode515:给定一颗二叉树的根节点root,请找出该二叉树中每一层的最大值
在得到一层之后使用一个变量来记录当前得到的最大值:
class Node:
def __init__(self, val=-1, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Tree:
def __init__(self, root=None):
self.root = root
def init_tree(self):
node_5 = Node(5)
node_3 = Node(3)
node_9 = Node(9)
node_3 = Node(3, node_5, node_3)
node_2 = Node(2, None, node_9)
root = Node(1, node_3, node_2)
return root
class LargestValues:
def largestValues(self, root):
if not root:
return []
ans = []
q = [root]
while q:
maxVal = -1
tmp = q
q = []
for node in tmp:
maxVal = max(maxVal, node.val)
if node.left:
q.append(node.left)
if node.right:
q.append(node.right)
ans.append(maxVal)
return ans
if __name__ == "__main__":
tree = Tree()
root = tree.init_tree()
largestValues = LargestValues()
res = largestValues.largestValues(root)
print(res)
3.2 在每个树行中找平均值
LeetCode 637:要求给定一个非空二叉树,返回一个由每层节点平均值组成的数组
import collections
class Node:
def __init__(self, val=-1, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Tree:
def __init__(self, root=None):
self.root = root
def init_tree(self):
node_9 = Node(9)
node_15 = Node(15)
node_7 = Node(7)
node_20 = Node(20, node_15, node_7)
root = Node(3, node_9, node_20)
return root
class AverageOfLevels:
def averageOfLevels(self, root):
if not root:
return []
q = collections.deque()
q.append(root)
res = []
while q:
n = len(q)
sum = 0
for _ in range(n):
node = q.popleft()
sum += node.val
if node.left:
q.append(node.left)
if node.right:
q.append(node.right)
res.append(sum/n)
return res
if __name__ == "__main__":
tree = Tree()
root = tree.init_tree()
averageOfLevels = AverageOfLevels()
res = averageOfLevels.averageOfLevels(root)
print(res)
3.3 二叉树的右视图
LeetCode 199:给定一个二叉树的根节点root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧能看到的节点值。
3.4 最底层最左边
正常执行层次遍历,不管最底层由几个元素,最后一个输出的一定是最底层最右的元素,每一层都是先反转再放入队列,就可以让最后一个输出的是最左的。
nonlocal声明的变量不是局部变量,也不是全局变量,而是外部嵌套函数内的变量
class Node:
def __init__(self, val=-1, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Tree:
def __init__(self, root=None):
self.root = root
def init_tree(self):
node_9 = Node(9)
node_15 = Node(15)
node_7 = Node(7)
node_20 = Node(20, node_15, node_7)
root = Node(3, node_9, node_20)
return root
class FindBottomLeftValue:
def findBottomLeftValue(self, root):
curVal = curHeight = 0
def dfs(node, height):
if node is None:
return
height += 1
dfs(node.right, height)
dfs(node.left, height)
# 注意right和left的上下位置和下边判定条件的关系
nonlocal curVal, curHeight
if height > curHeight:
curHeight = height
curVal = node.val
dfs(root, 0)
return curVal
if __name__ == "__main__":
tree = Tree()
root = tree.init_tree()
findBottomLeftValue = FindBottomLeftValue()
res = findBottomLeftValue.findBottomLeftValue(root)
print(res)