LeetCode刷题记录---二叉树专题

每次刷到二叉树算法题将在此博文更新~~~

以下具体理论知识,请参考Carl哥整理的:点击进入
【注:以下刷题顺序均按Carl哥的进行,Carl哥的微信公众号:代码随想录。欢迎大家关注!】

理论基础:

⭐一、二叉树种类

  1. 满二叉树
  2. 完全二叉树
  3. 二叉搜索树
  4. 平衡二叉搜索树

⭐二、二叉树的存储方式

  1. 顺序存储(数组)
  2. 链式存储(链表)

⭐三、二叉树的遍历方式

  1. DFS(前中后序遍历:递归,非递归:栈)
  2. BFS(层序遍历:队列)

⭐四、二叉树的定义
python中节点定义如下:

class TreeNode: 
    def __init__(self, value):
        self.value = value
        self.left = None
        self.right = None

递归3要素:

1. 确定递归函数的参数和返回值:
2. 确定终止条件:
3. 确定单层递归的逻辑:



题目:

难度 题目
简单 二叉树的前序遍历【递归,非递归(栈)】
简单 二叉树的后序遍历【递归,非递归(栈)】
简单 二叉树的中序遍历【递归,非递归(栈)】
中等 二叉树的层序遍历
中等 二叉树的层次遍历II
中等 二叉树的右视图
简单 二叉树的层平均值
中等 N叉树的前序遍历
中等 在每个树行中找最大值
中等 填充每个节点的下一个右侧节点指针
中等 填充每个节点的下一个右侧节点指针 II
简单 翻转二叉树【前、中、后、层序遍历】
简单 对称二叉树
中等 二叉树的最大深度
中等 二叉树的最小深度


⭐二叉树的前序遍历:

LeetCode刷题记录---二叉树专题_第1张图片
前序遍历:根左右。
解法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
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


⭐二叉树的后序遍历:

LeetCode刷题记录---二叉树专题_第2张图片
后序遍历:左右根。
解法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
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


⭐二叉树的中序遍历:

LeetCode刷题记录---二叉树专题_第3张图片
中序遍历:左根右。
解法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
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


⭐二叉树的层序遍历:

LeetCode刷题记录---二叉树专题_第4张图片
后面跟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 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


⭐二叉树的层次遍历II:

LeetCode刷题记录---二叉树专题_第5张图片

# 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]


⭐二叉树的右视图:

LeetCode刷题记录---二叉树专题_第6张图片

# 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


⭐二叉树的层平均值:

LeetCode刷题记录---二叉树专题_第7张图片

# 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


⭐N叉树的层序遍历:

LeetCode刷题记录---二叉树专题_第8张图片

"""
# 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


⭐在每个树行中找最大值:

LeetCode刷题记录---二叉树专题_第9张图片

# 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


⭐填充每个节点的下一个右侧节点指针:

在这里插入图片描述
LeetCode刷题记录---二叉树专题_第10张图片
(解法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)的做法:

LeetCode刷题记录---二叉树专题_第11张图片
从下图看,无非两种连接方式:

  1. node.left.next = node.right
  2. node.right.next = node.next.left
    LeetCode刷题记录---二叉树专题_第12张图片
     所以设计一个循环,通过当前层控制下一层节点的连接即可实现。
     设置一个标志节点记录每一层的首节点,即当前层第一个节点的左孩子节点(不用队列)。再设置一个节点记录当前节点,方便每次循环将其右移。
"""
# 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


⭐填充每个节点的下一个右侧节点指针II:

LeetCode刷题记录---二叉树专题_第13张图片
(解法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


⭐翻转二叉树:

LeetCode刷题记录---二叉树专题_第14张图片
 遍历的过程中去翻转每⼀个节点的左右孩子就可以达到整体翻转的效果。
 前,后,层序遍历均可以,而中序遍历则会将左边节点翻转两次,而右边节点没翻转,所以直接用中序遍历的代码不行,得修改修改后才能解决该题,可以自己对着一棵树思考下这个交换左右孩子节点的过程就明白了。

(解法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


⭐对称二叉树:

LeetCode刷题记录---二叉树专题_第15张图片
解法一: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

⭐二叉树的最大深度:
⭐二叉树的最小深度:

你可能感兴趣的:(算法与数据结构,二叉树,leetcode,数据结构,算法)