leetcode(9)二叉树遍历系列题目
二叉树的种类
满二叉树
如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。
深度为k,有2^k-1个节点
完全二叉树
在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2^(h-1) 个节点。
二叉搜索树
节点的值是有序的。
- 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
- 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
- 它的左、右子树也分别为二叉排序树
平衡二叉搜索树
又被称为AVL(Adelson-Velsky and Landis)树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
C++中map、set、multimap,multiset的底层实现都是平衡二叉搜索树,所以map、set的增删操作时间时间复杂度是logn,而unordered_map底层实现是哈希表。
二叉树的遍历方式
深度优先遍历:递归
144.二叉树的前序遍历
class Solution:
def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
res = []
def traversal(root):
if not root:
return
res.append(root.val)
traversal(root.left)
traversal(root.right)
traversal(root)
return res
145.二叉树的后序遍历
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
res = []
def traversal(root):
if not root:
return
traversal(root.left)
traversal(root.right)
res.append(root.val)
traversal(root)
return res
94.二叉树的中序遍历
class Solution:
def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
res = []
def traversal(root):
if not root:
return
traversal(root.left)
res.append(root.val)
traversal(root.right)
traversal(root)
return res
深度优先遍历:迭代(借助栈)
144.二叉树的前序遍历
class Solution:
def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
# 根结点为空则返回空列表
if not root:
return []
res = []
stack = [root]
while stack:
node = stack.pop()
# 中结点先处理
res.append(node.val)
# 右孩子先入栈
if node.right:
stack.append(node.right)
# 左孩子后入栈
if node.left:
stack.append(node.left)
return res
145.二叉树的后序遍历
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
if not root:
return []
res = []
stack = [root]
while stack:
node = stack.pop()
# 中结点先处理
res.append(node.val)
# 左孩子先入栈
if node.left:
stack.append(node.left)
# 右孩子后入栈
if node.right:
stack.append(node.right)
# 将最终的数组翻转
return res[::-1]
94.二叉树的中序遍历
class Solution:
def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
if not root:
return []
res = []
stack = [] # 不能提前将root结点加入stack中
cur = root
while cur or stack:
# 先迭代访问最底层的左子树结点
if cur:
stack.append(cur)
cur = cur.left
else:
# 到达最左结点后处理栈顶结点
cur = stack.pop()
res.append(cur.val)
# 取栈顶元素右结点
cur = cur.right
return res
广度优先遍历(层序遍历):迭代(借助队列)
deque来自collections模块,不在力扣平台时,需要手动写入
'from collections import deque' 导入
deque相比list的好处是,list的pop(0)是O(n)复杂度,deque的popleft()是O(1)复杂度
102. 二叉树的层序遍历
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
if not root:
return []
res = []
from collections import deque
que = deque([root])
while que:
size = len(que)
ans = []
for _ in range(size):
cur = que.popleft()
ans.append(cur.val)
if cur.left:
que.append(cur.left)
if cur.right:
que.append(cur.right)
res.append(ans)
return res
103. 二叉树的锯齿形层序遍历
注意:与102. 二叉树的层序遍历 的区别是偶数层加一步反转即可
class Solution:
def zigzagLevelOrder(self, root: TreeNode) -> List[List[int]]:
if not root:
return []
res = []
from collections import deque
que = deque([root])
flag = False
while que:
size = len(que)
ans = []
for _ in range(size):
cur = que.popleft()
ans.append(cur.val)
if cur.left:
que.append(cur.left)
if cur.right:
que.append(cur.right)
if flag:
ans = ans[::-1] # 反转字符串
flag = not flag
res.append(ans)
return res
107. 二叉树的层序遍历 II
注意:与102. 二叉树的层序遍历 的区别是最后加一步反转即可
class Solution:
def levelOrderBottom(self, root: TreeNode) -> List[List[int]]:
if not root:
return []
res = []
from collections import deque
que = deque([root])
while que:
size = len(que)
ans = []
for _ in range(size):
cur = que.popleft()
ans.append(cur.val)
if cur.left:
que.append(cur.left)
if cur.right:
que.append(cur.right)
res.append(ans)
res.reverse() # 加这一步反转
return res
199. 二叉树的右视图
注意:与102. 二叉树的层序遍历 的区别是判断是否遍历到单层的最后一个元素,如果是,就放进result数组中,最后返回result就可以了。
class Solution:
def rightSideView(self, root: Optional[TreeNode]) -> List[int]:
if not root:
return []
res = []
from collections import deque
que = deque([root])
while que:
size = len(que)
for i in range(size):
cur = que.popleft()
if i == size - 1: # 判断是否是最后一个
res.append(cur.val)
if cur.left:
que.append(cur.left)
if cur.right:
que.append(cur.right)
return res
637. 二叉树的层平均值
注意:与102. 二叉树的层序遍历 的区别是层序遍历的时候把一层求总和再取均值。
class Solution:
def averageOfLevels(self, root: Optional[TreeNode]) -> List[float]:
if not root:
return []
res = []
from collections import deque
que = deque([root])
while que:
size = len(que)
sum_ = 0
for _ in range(size):
cur = que.popleft()
sum_ += cur.val # 求和
if cur.left:
que.append(cur.left)
if cur.right:
que.append(cur.right)
res.append(sum_ / size) # 取平均
return res
429. N 叉树的层序遍历
注意:与102. 二叉树的层序遍历 的区别是一个节点有多个孩子
class Solution:
def levelOrder(self, root: 'Node') -> List[List[int]]:
if not root:
return []
res = []
from collections import deque
que = deque([root])
while que:
size = len(que)
ans = []
for _ in range(size):
cur = que.popleft()
ans.append(cur.val)
if cur.children:
que.extend(cur.children) # 注意使用extend函数
res.append(ans)
return res
515. 在每个树行中找最大值
注意:与102. 二叉树的层序遍历 的区别是取每一行的最大值
class Solution:
def largestValues(self, root: Optional[TreeNode]) -> List[int]:
if not root:
return []
res = []
from collections import deque
que = deque([root])
while que:
size = len(que)
ans = []
for _ in range(size):
cur = que.popleft()
ans.append(cur.val)
if cur.left:
que.append(cur.left)
if cur.right:
que.append(cur.right)
res.append(max(ans)) # 将最大值存入
return res
116. 填充每个节点的下一个右侧节点指针
117. 填充每个节点的下一个右侧节点指针 II
注意:与102. 二叉树的层序遍历 的区别是在单层遍历的时候让指针指向其下一个右侧节点,如果是该层最后一个节点,则跳出循环
class Solution:
def connect(self, root: 'Optional[Node]') -> 'Optional[Node]':
if not root:
return root
from collections import deque
que = deque([root])
while que:
size = len(que)
for i in range(size):
cur = que.popleft()
if cur.left:
que.append(cur.left)
if cur.right:
que.append(cur.right)
if i == size - 1: # 如果是该层最后一个节点,则跳出循环
break
cur.next = que[0] # 让这个指针指向其下一个右侧节点
return root
104. 二叉树的最大深度
注意:与102. 二叉树的层序遍历 的区别是最大的深度就是二叉树的层数,记录层数最后返回即可
递归写法:
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
if not root:return 0
return max(self.maxDepth(root.left), self.maxDepth(root.right)) + 1
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
if not root:
return 0
res = 0
from collections import deque
que = deque([root])
while que:
size = len(que)
for _ in range(size):
cur = que.popleft()
if cur.left:
que.append(cur.left)
if cur.right:
que.append(cur.right)
res += 1 #记录层数
return res
111. 二叉树的最小深度
注意:与104. 二叉树的最大深度 的区别是只有当左右孩子都为空的时候,才说明遍历的最低点了。
class Solution:
def minDepth(self, root: TreeNode) -> int:
if not root:
return 0
res = 1 # 注意初始化为1
from collections import deque
que = deque([root])
while que:
size = len(que)
for _ in range(size):
cur = que.popleft()
if cur.left:
que.append(cur.left)
if cur.right:
que.append(cur.right)
if not cur.left and not cur.right: # 左右节点都没有时
return res
res += 1 # 记录层数
return res
226. 翻转二叉树
递归法:前序遍历或后序遍历:
class Solution:
def invertTree(self, root: TreeNode) -> TreeNode:
if not root:
return root
self.invertTree(root.left)
self.invertTree(root.right)
# 处理中间节点放在前面或者后面都可以
root.left, root.right = root.right, root.left
return root
迭代法:深度优先遍历(前序遍历):
class Solution:
def invertTree(self, root: TreeNode) -> TreeNode:
if not root:
return root
stack = [root]
while stack:
node = stack.pop()
node.left, node.right = node.right, node.left #中
if node.left:
stack.append(node.left) #左(左右顺序好像不影响)
if node.right:
stack.append(node.right) #右
return root
迭代法:广度优先遍历(层序遍历):
class Solution:
def invertTree(self, root: TreeNode) -> TreeNode:
if not root:
return root
from collections import deque
que = deque([root])
while que:
size = len(que)
for _ in range(size):
cur = que.popleft()
cur.left, cur.right = cur.right, cur.left
if cur.left:
que.append(cur.left)
if cur.right:
que.append(cur.right)
return root