102. 二叉树的层序遍历
难度:☆2
a. 迭代法:层序遍历+队列
队列和数组。deque实现一个先进先出的队列,队列里面保存二叉树每一层的节点。通过两层循环遍历所有节点,保存在数组里。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
result = []
stack = deque()
if root:
stack.append(root)
while stack:
size = len(stack)
level = []
for _ in range(size):
node = stack.popleft()
level.append(node.val)
if node.left:
stack.append(node.left)
if node.right:
stack.append(node.right)
result.append(level)
return result
Python Doc: deque相比list的好处是,list的pop(0)是O(n)复杂度,deque的popleft()是O(1)复杂度。
107. 二叉树的层序遍历 II
难度:☆2
a. 迭代法:层序遍历+队列
队列和数组。deque实现一个先进先出的队列,队列里面保存二叉树每一层的节点。通过两层循环遍历所有节点,保存在数组里。翻转结果数组,实现自底向上的层序遍历。
class Solution:
def levelOrderBottom(self, root: Optional[TreeNode]) -> List[List[int]]:
results = []
queue = deque()
if root:
queue.append(root)
while queue:
size = len(queue)
result = []
for _ in range(size):
cur = queue.popleft()
result.append(cur.val)
if cur.left:
queue.append(cur.left)
if cur.right:
queue.append(cur.right)
results.append(result)
results.reverse()
return results
199. 二叉树的右视图
难度:☆2
a. 迭代法:层序遍历+队列
队列和数组。二叉树的层序遍历。deque实现一个先进先出的队列,队列里面保存二叉树每一层的节点。通过两层循环遍历所有节点,把每一层末尾的节点数值保存在数组里返回。
class Solution:
def rightSideView(self, root: Optional[TreeNode]) -> List[int]:
result = []
queue = deque()
if root:
queue.append(root)
while queue:
size = len(queue)
right = queue[-1]
result.append(right.val)
for _ in range(size):
cur = queue.popleft()
if cur.left:
queue.append(cur.left)
if cur.right:
queue.append(cur.right)
return result
637. 二叉树的层平均值
难度:☆2
a. 迭代法:层序遍历+队列
队列和数组。类似102题层序遍历。deque实现一个先进先出的队列,队列里面保存二叉树每一层的节点。通过两层循环遍历所有节点,保存在数组里,并求每一层的节点之和。最后将每一层的平均数存入结果数组。
class Solution:
def averageOfLevels(self, root: Optional[TreeNode]) -> List[float]:
result = []
queue = deque()
if root:
queue.append(root)
while queue:
size = len(queue)
total = 0
for _ in range(size):
cur = queue.popleft()
total += cur.val
if cur.left:
queue.append(cur.left)
if cur.right:
queue.append(cur.right)
result.append(total / size)
return result
429. N 叉树的层序遍历
难度:☆3
a. 迭代法:层序遍历+队列
队列和数组。类似102题层序遍历。deque实现一个先进先出的队列,队列里面保存二叉树每一层的节点。通过两层循环遍历所有节点,将节点的N个子节点保存在结果数组里返回。
class Solution:
def levelOrder(self, root: 'Node') -> List[List[int]]:
results = []
queue = deque()
if root:
queue.append(root)
while queue:
size = len(queue)
level = []
for _ in range(size):
cur = queue.popleft()
level.append(cur.val)
for i in range(len(cur.children)):
queue.append(cur.children[i])
results.append(level)
return results
用deque的extend方法的另一种写法:
class Solution:
def levelOrder(self, root: 'Node') -> List[List[int]]:
level_order = []
if not root:
return level_order
que = deque([root])
while que:
level = []
for _ in range(len(que)):
cur = que.popleft()
level.append(cur.val)
if cur.children:
que.extend(cur.children)
level_order.append(level)
return level_order
515. 在每个树行中找最大值
难度:☆2
a. 迭代法:层序遍历+队列
队列和数组。类似102题层序遍历。deque实现一个先进先出的队列,队列里面保存二叉树每一层的节点。通过两层循环遍历所有节点,将每层的最大节点保存在数组里返回。
class Solution:
def largestValues(self, root: Optional[TreeNode]) -> List[int]:
result = []
queue = deque()
if root:
queue.append(root)
while queue:
size = len(queue)
largest = -sys.maxsize
for _ in range(size):
cur = queue.popleft()
if cur.val > largest:
largest = cur.val
if cur.left:
queue.append(cur.left)
if cur.right:
queue.append(cur.right)
result.append(largest)
return result
Python Doc: sys.maxsize 最大整数。
116. 填充每个节点的下一个右侧节点指针
难度:☆2
a. 迭代法:层序遍历+队列
队列,二叉树的层序遍历。题意要求满二叉树。deque实现一个先进先出的队列,队列里面保存二叉树每一层的节点。通过两层循环遍历所有节点,让每一层的节点指向下一个,最后一个节点不处理(默认指向None)。
class Solution:
def connect(self, root: 'Optional[Node]') -> 'Optional[Node]':
queue = deque()
if root:
queue.append(root)
while queue:
size = len(queue)
for i in range(size):
cur = queue.popleft()
if i < size - 1:
cur.next = queue[0]
if cur.left:
queue.append(cur.left)
if cur.right:
queue.append(cur.right)
return root
b. 迭代法:链表
first指向每层第一个节点,cur依次指向每层所有节点,对cur的左/右节点的next赋值,遍历所有节点。比队列的思维难度更高。
class Solution:
def connect(self, root: 'Optional[Node]') -> 'Optional[Node]':
first = root # 每层的第一个
while first:
cur = first
while cur: # 遍历每层的节点
if cur.left:
cur.left.next = cur.right # 找左节点的next
if cur.right and cur.next:
cur.right.next = cur.next.left # 找右节点的next
cur = cur.next # cur同层移动到下一节点
first = first.left # 从本层扩展到下一层
return root
117. 填充每个节点的下一个右侧节点指针 II
难度:☆2
a. 迭代法:层序遍历+队列
队列,二叉树的层序遍历。题意不同于116题限制满二叉树,代码完全同116题。也可以遍历每一层节点生成一个个列表,再对每一个列表串联成链表。
class Solution:
def connect(self, root: 'Node') -> 'Node':
queue = deque()
if root:
queue.append(root)
while queue:
size = len(queue)
for i in range(size):
cur = queue.popleft()
if i < size - 1:
cur.next = queue[0]
if cur.left:
queue.append(cur.left)
if cur.right:
queue.append(cur.right)
return root
226. 翻转二叉树
难度:☆3
a. 递归法:前序遍历
二叉树的前序遍历,递归法实现。
class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
if not root:
return root
root.left, root.right = root.right, root.left # 中
self.invertTree(root.left) # 左
self.invertTree(root.right) # 右
return root
b. 递归法:后序遍历
二叉树的后序遍历,递归法实现。
class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
if not root:
return root
self.invertTree(root.left) # 左
self.invertTree(root.right) # 右
root.left, root.right = root.right, root.left # 中
return root
c. 递归法:中序遍历
二叉树的中序遍历,递归法实现。易错注意:中序遍历中间节点的操作在中间,翻转左子树之后,还要再翻转左子树,因为翻转了中间节点的左右子树。
class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
if not root:
return root
self.invertTree(root.left) # 左
root.left, root.right = root.right, root.left # 中
self.invertTree(root.left) # 注意还是左
return root
d. 迭代法:前序遍历
二叉树的前序遍历,迭代法借助栈实现。
class Solution:
def invertTree(self, root: TreeNode) -> TreeNode:
if not root:
return root
st = [root]
while st:
node = st.pop()
node.left, node.right = node.right, node.left # 中
if node.left:
st.append(node.left) # 左
if node.right:
st.append(node.right) # 右
return root
e. 迭代法:后序遍历
二叉树的后序遍历,迭代法借助栈实现。
class Solution:
def invertTree(self, root: TreeNode) -> TreeNode:
if not root:
return root
st = [root]
while st:
node = st.pop()
if node.left:
st.append(node.left) # 左
if node.right:
st.append(node.right) # 右
node.left, node.right = node.right, node.left # 中
return root
f. 迭代法:中序遍历
二叉树的中序遍历,迭代法借助栈实现。易错注意:中序遍历中间节点的操作在中间,翻转左子树之后,还要再翻转左子树,因为翻转了中间节点的左右子树。
class Solution:
def invertTree(self, root: TreeNode) -> TreeNode:
if not root:
return root
st = [root]
while st:
node = st.pop()
if node.left:
st.append(node.left) # 左
node.left, node.right = node.right, node.left # 中
if node.left:
st.append(node.left) # 注意还是左
return root
g. 迭代法:层序遍历
二叉树的层序遍历,迭代法借助队列实现。deque实现一个先进先出的队列,队列里面保存二叉树每一层的节点。通过两层循环遍历所有节点,交换每个节点的左右孩子,并把左右孩子加到队列里。注意,交换左右孩子,也可以放在“把左右孩子加到队列里”的操作后面。
class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
queue = deque()
if root:
queue.append(root)
while queue:
size = len(queue)
for _ in range(size):
cur = queue.popleft()
cur.left, cur.right = cur.right, cur.left
if cur.left:
queue.append(cur.left)
if cur.right:
queue.append(cur.right)
return root
101. 对称二叉树
难度:☆3
a. 递归法:后序遍历
二叉树的后序遍历,递归法实现。探究中间父节点的左子树和右子树是否对称。递归三部曲:确定递归函数的参数和返回值,确定终止条件,确定单层递归的逻辑。
class Solution:
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
if root is None: return True
return self.compare(root.left, root.right)
def compare(self, left, right):
if left is None and right is None: return True
elif left is None and right: return False
elif left and right is None: return False
elif left.val != right.val: return False
outside = self.compare(left.left, right.right) # 比较左子树的左孩子、右子树的右孩子
inside = self.compare(left.right, right.left) # 比较左子树的右孩子、右子树的左孩子
result = inside and outside # 返回上层中间节点(父节点)
return result
简化写法:
class Solution:
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
if root is None: return True
return self.compare(root.left, root.right)
def compare(self, leftTree: TreeNode, rightTree: TreeNode) -> bool:
if leftTree is None and rightTree: return False
elif leftTree and rightTree is None: return False
elif leftTree is None and rightTree is None: return True
elif leftTree.val != rightTree.val: return False
return self.compare(leftTree.left, rightTree.right) and self.compare(leftTree.right, rightTree.left)
更加精简:
class Solution:
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
if root is None:
return True
return self.check(root.left, root.right)
def check(self, left: TreeNode, right: TreeNode) -> bool:
if left is None or right is None:
return left is right
if left.val != right.val:
return False
return self.check(left.right, right.left) and self.check(left.left, right.right)
b. 迭代法:队列
迭代法用队列实现,关键是把要比较的节点放进去,再pop出来做比较。
class Solution:
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
if root is None:
return True
queue = deque()
queue.append(root.left)
queue.append(root.right)
while queue:
leftNode = queue.popleft() # 队列:先入先出
rightNode = queue.popleft()
if leftNode is None and rightNode is None:
continue
if leftNode is None or rightNode is None or leftNode.val != rightNode.val:
return False
queue.append(leftNode.left)
queue.append(rightNode.right)
queue.append(leftNode.right)
queue.append(rightNode.left)
return True
c. 迭代法:栈
迭代法用栈实现,关键是把要比较的节点放进去,再pop出来做比较。和队列实现的代码基本一致,注意栈是先入后出。
class Solution:
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
if root is None:
return True
stack = []
stack.append(root.left)
stack.append(root.right)
while stack:
rightNode = stack.pop() # 栈:先入后出
leftNode = stack.pop()
if leftNode is None and rightNode is None:
continue
if leftNode is None or rightNode is None or leftNode.val != rightNode.val:
return False
stack.append(leftNode.left)
stack.append(rightNode.right)
stack.append(leftNode.right)
stack.append(rightNode.left)
return True