以下具体理论知识,请参考Carl哥整理的:点击进入
【注:以下刷题顺序均按Carl哥的进行,Carl哥的微信公众号:代码随想录。欢迎大家关注!】
⭐一、二叉树种类
⭐二、二叉树的存储方式
⭐三、二叉树的遍历方式
⭐四、二叉树的定义
python中节点定义如下:
class TreeNode:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
1. 确定递归函数的参数和返回值:
2. 确定终止条件:
3. 确定单层递归的逻辑:
难度 | 题目 |
---|---|
简单 | 二叉树的前序遍历【递归,非递归(栈)】 |
简单 | 二叉树的后序遍历【递归,非递归(栈)】 |
简单 | 二叉树的中序遍历【递归,非递归(栈)】 |
中等 | 二叉树的层序遍历 |
中等 | 二叉树的层次遍历II |
中等 | 二叉树的右视图 |
简单 | 二叉树的层平均值 |
中等 | N叉树的前序遍历 |
中等 | 在每个树行中找最大值 |
中等 | 填充每个节点的下一个右侧节点指针 |
中等 | 填充每个节点的下一个右侧节点指针 II |
简单 | 翻转二叉树【前、中、后、层序遍历】 |
简单 | 对称二叉树 |
中等 | 二叉树的最大深度 |
中等 | 二叉树的最小深度 |
# 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 preorderTraversal(self, root: TreeNode) -> List[int]:
res = []
def traversal(root):
if root == None: return
# 前序遍历
res.append(root.val) # 根
traversal(root.left) # 左
traversal(root.right) # 右
traversal(root)
return res
解法2:非递归(栈)
# 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 preorderTraversal(self, root: TreeNode) -> List[int]:
if root == None: return []
stack = []
stack.append(root)
res = []
# 根左右
while stack:
node = stack.pop()
if node != None:
# 右孩子先进后出
if node.right:
stack.append(node.right)
if node.left:
stack.append(node.left)
# 将根节点后加个None,当读到None时说明要处理根节点了,相当于做个标记
stack.append(node)
stack.append(None)
elif node==None:
node = stack.pop()
res.append(node.val)
return res
# 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 postorderTraversal(self, root: TreeNode) -> List[int]:
res = []
def traversal(root):
if root == None: return
# 后序遍历
traversal(root.left) # 左
traversal(root.right) # 右
res.append(root.val) # 根
traversal(root)
return res
解法2:非递归(栈)
# 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 postorderTraversal(self, root: TreeNode) -> List[int]:
if root == None: return []
stack = []
stack.append(root)
res = []
# 左右根
while stack:
node = stack.pop()
if node != None:
# 将根节点后加个None,当读到None时说明要处理根节点了,相当于做个标记
stack.append(node)
stack.append(None)
# 右孩子先进后出
if node.right:
stack.append(node.right)
if node.left:
stack.append(node.left)
elif node==None:
node = stack.pop()
res.append(node.val)
return res
# 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 inorderTraversal(self, root: TreeNode) -> List[int]:
res = []
def traversal(root):
if root == None: return
# 中序遍历
traversal(root.left) # 左
res.append(root.val) # 根
traversal(root.right) # 右
traversal(root)
return res
解法2:非递归(栈)
# 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 inorderTraversal(self, root: TreeNode) -> List[int]:
if root == None: return []
stack = []
stack.append(root)
res = []
# 左根右
while stack:
node = stack.pop()
if node != None:
# 右孩子先进后出
if node.right:
stack.append(node.right)
# 将根节点后加个None,当读到None时说明要处理根节点了,相当于做个标记
stack.append(node)
stack.append(None)
if node.left:
stack.append(node.left)
elif node==None:
node = stack.pop()
res.append(node.val)
return res
# 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
import collections
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
if root == None: return []
queue = collections.deque()
queue.append(root)
res = []
while queue:
temp_list = []
queue_len = len(queue)
for _ in range(queue_len):
new_node = queue.popleft()
temp_list.append(new_node.val) # 保存每一层的结果
if new_node.left:
queue.append(new_node.left)
if new_node.right:
queue.append(new_node.right)
res.append(temp_list)
return res
# 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
import collections
class Solution:
def levelOrderBottom(self, root: TreeNode) -> List[List[int]]:
if root == None: return []
queue = collections.deque()
queue.append(root)
res = []
while queue:
temp_list = []
queue_len = len(queue)
for _ in range(queue_len):
new_node = queue.popleft()
temp_list.append(new_node.val)
if new_node.left: queue.append(new_node.left)
if new_node.right: queue.append(new_node.right)
res.append(temp_list)
return res[::-1]
# 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
import collections
class Solution:
def rightSideView(self, root: TreeNode) -> List[int]:
if root == None: return []
queue = collections.deque()
queue.append(root)
res = []
while queue:
queue_len = len(queue)
for i in range(queue_len):
new_node = queue.popleft()
if i == queue_len-1: res.append(new_node.val)
if new_node.left: queue.append(new_node.left)
if new_node.right: queue.append(new_node.right)
return res
# 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 averageOfLevels(self, root: Optional[TreeNode]) -> List[float]:
if root == None: return []
queue = collections.deque()
queue.append(root)
res = []
while queue:
queue_len = len(queue)
sum_ = 0
for i in range(queue_len):
new_node = queue.popleft()
sum_ += new_node.val
if new_node.left: queue.append(new_node.left)
if new_node.right: queue.append(new_node.right)
res.append(sum_/queue_len)
return res
"""
# Definition for a Node.
class Node:
def __init__(self, val=None, children=None):
self.val = val
self.children = children
"""
import collections
class Solution:
def levelOrder(self, root: 'Node') -> List[List[int]]:
if root == None: return []
queue = collections.deque()
queue.append(root)
res = []
while queue:
queue_len = len(queue)
temp_list = []
for _ in range(queue_len):
new_node = queue.popleft()
temp_list.append(new_node.val)
if new_node.children:
for child in new_node.children:
queue.append(child)
res.append(temp_list)
return res
# 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 largestValues(self, root: TreeNode) -> List[int]:
if root == None: return []
queue = collections.deque()
queue.append(root)
res = []
while queue:
queue_len = len(queue)
max_ = -float('inf')
for i in range(queue_len):
new_node = queue.popleft()
if new_node.val > max_: max_ = new_node.val
if new_node.left: queue.append(new_node.left)
if new_node.right: queue.append(new_node.right)
res.append(max_)
return res
(解法1:BFS-队列)
这题关键就是在每一层的遍历时,在新节点出列后,用新节点的next指向队首元素:
"""
# Definition for a Node.
class Node:
def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None):
self.val = val
self.left = left
self.right = right
self.next = next
"""
import collections
class Solution:
def connect(self, root: 'Node') -> 'Node':
if not root: return root
queue = collections.deque()
queue.append(root)
while queue:
queuelen = len(queue)
for i in range(queuelen):
newnode = queue.popleft()
if i<queuelen-1:
newnode.next = queue[0]
if newnode.left: queue.append(newnode.left)
if newnode.right: queue.append(newnode.right)
return root
因为上面用到了队列存储每一层的节点,所以空间复杂度为O(N),又因为每个节点到会被访问一次所以时间复杂度为O(N)。
下面考虑空间复杂度为常量级O(1)的做法:
从下图看,无非两种连接方式:
node.left.next = node.right
node.right.next = node.next.left
"""
# Definition for a Node.
class Node:
def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None):
self.val = val
self.left = left
self.right = right
self.next = next
"""
import collections
class Solution:
def connect(self, root: 'Node') -> 'Node':
if root == None: return root
head = root
# 控制所有层是否遍历处理完
while head.left:
# 记录当前层当前节点
cur = head
# 控制当前层是否遍历完
while cur:
# 情况1:
cur.left.next = cur.right
# 情况2:
if cur.next:
cur.right.next = cur.next.left
cur = cur.next # 移动到当前层的下一节点
head = head.left # 赋值为下一层的最左节点
return root
(解法1:BFS-队列)
这题关键就是在每一层的遍历时,在新节点出列后,用新节点的next指向队首元素(代码和《填充每个节点的下一个右侧节点指针》一摸一样即可):
"""
# Definition for a Node.
class Node:
def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None):
self.val = val
self.left = left
self.right = right
self.next = next
"""
import collections
class Solution:
def connect(self, root: 'Node') -> 'Node':
if not root: return root
queue = collections.deque()
queue.append(root)
while queue:
queuelen = len(queue)
for i in range(queuelen):
newnode = queue.popleft()
if i<queuelen-1:
newnode.next = queue[0]
if newnode.left: queue.append(newnode.left)
if newnode.right: queue.append(newnode.right)
return root
因为上面用到了队列存储每一层的节点,所以空间复杂度为O(N),又因为每个节点到会被访问一次所以时间复杂度为O(N)。
下面考虑空间复杂度为常量级O(1)的做法,因为《填充每个节点的下一个右侧节点指针》那题是完全二叉树,这题只是二叉树:
"""
# Definition for a Node.
class Node:
def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None):
self.val = val
self.left = left
self.right = right
self.next = next
"""
import collections
class Solution:
def connect(self, root: 'Node') -> 'Node':
if root == None: return root
head = root
# 主要做法就是遍历当前层来控制下一层的连接
while head:
cur = head # 当前层节点,遍历当前层来连接下一层
dummy_head = Node(0) # 创建一个虚拟头结点,方便统一操作
pre = dummy_head #用来记录下一层的连接
while cur:
if cur.left:
pre.next = cur.left
pre = pre.next
if cur.right:
pre.next = cur.right
pre = pre.next
cur = cur.next
head = dummy_head.next # 指向刚连接好的层的头节点,继续把它的下一层连接好
return root
遍历的过程中去翻转每⼀个节点的左右孩子就可以达到整体翻转的效果。
前,后,层序遍历均可以,而中序遍历则会将左边节点翻转两次,而右边节点没翻转,所以直接用中序遍历的代码不行,得修改修改后才能解决该题,可以自己对着一棵树思考下这个交换左右孩子节点的过程就明白了。
(解法1:前序遍历-递归DFS)
# 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 invertTree(self, root: TreeNode) -> TreeNode:
if root == None: return
#根,在根位置将其左右孩子调换位置
root.left, root.right = root.right, root.left
#左
self.invertTree(root.left)
# 右
self.invertTree(root.right)
return root
(解法2:前序遍历-迭代-栈)
# 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 invertTree(self, root: TreeNode) -> TreeNode:
if root == None: return root
stack = []
stack.append(root)
while stack:
node = stack.pop()
if node != None:
if node.right:
stack.append(node.right)
if node.left:
stack.append(node.left)
stack.append(node)
stack.append(None)
elif node == None:
node = stack.pop()
# 根处交换左右孩子节点
node.left, node.right = node.right, node.left
return root
(解法3:层序遍历-BFS-队列)
# 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
import collections
class Solution:
def invertTree(self, root: TreeNode) -> TreeNode:
if root == None: return root
queue = collections.deque()
queue.append(root)
while queue:
node = queue.popleft()
# 节点出列,翻转左右孩子节点
node.left, node.right = node.right, node.left
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return root
解法一:DFS
分别递归遍历外层和内层来判断是否对称,若外层和内层均对称则总的就对称。
# 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 isSymmetric(self, root: TreeNode) -> bool:
if root == None:
return True
return self.compare(root.left, root.right)
def compare(self, left, right):
# 处理节点为空的情况
if left==None and right==None: return True
elif left==None and right!=None: return False
elif left!=None and right==None: return False
elif left.val != right.val: return False
# 递归判断外层对称情况
out_bool = self.compare(left.left, right.right)
# 递归判断内层对称情况
in_bool = self.compare(left.right, right.left)
return out_bool and in_bool
解法二:BFS
其实用队列,栈,数组都是没问题的,因为我们只要成对成对的判断是否相等就行。
# 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
import collections
class Solution:
def isSymmetric(self, root: TreeNode) -> bool:
if root == None: return True
queue = collections.deque()
queue.append(root.left)
queue.append(root.right)
while queue:
left = queue.popleft()
right = queue.popleft()
if left==None and right==None: continue
if left==None or right==None or left.val!=right.val: return False
queue.append(left.left)
queue.append(right.right)
queue.append(left.right)
queue.append(right.left)
return True
⭐二叉树的最大深度:
⭐二叉树的最小深度: