【LeetCode】树专题

目录

 

注意

98. 验证二叉搜索树

94. 二叉树的中序遍历

101. 对称二叉树

105. 从前序与中序遍历序列构造二叉树

102. 二叉树的层序遍历

236. 二叉树的最近公共祖先

543. 二叉树的直径

124. 二叉树中的最大路径和

173. 二叉搜索树迭代器

297. 二叉树的序列化与反序列化


注意

主要和b站大雪菜一起刷题,宝藏up主(https://www.bilibili.com/video/BV19t411w7Ep/?spm_id_from=333.788.videocard.0)

98. 验证二叉搜索树

思路:

  • 这个题只需要判断是否是BST即可
  • 题目条件限制的也很清晰,不会出现节点相等的情况
  • 考虑划分范围的做法,假如当前节点的值为x,则左子树的取值范围为[-∞,x-1],右子树的取值范围为[x+1,∞]
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def isValidBST(self, root: TreeNode) -> bool:
        return self.dfs(root, -float('INF'), float('INF'))
    
    def dfs(self, root, min_val, max_val):
        if not root:
            return True
        if root.val>max_val or root.val

94. 二叉树的中序遍历

思路:

  • 其实递归版本的中序遍历就是系统开了个栈
  • 所以直接使用栈进行中序遍历即可
  • 将整棵树的最左边的一条链压入栈中
  • 每次取出栈顶元素,并将其右子树压入栈中
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:
        # 开栈
        stack = []
        # 结果
        res = []
        # 遍历指针
        p = root
        # 当没有遍历完或者栈不为空时
        while p or stack:
            # 左节点入栈
            while p:
                stack.append(p)
                p = p.left
            # 出栈
            p = stack.pop()
            res.append(p.val)
            p = p.right
        return res

101. 对称二叉树

思路:

  • 递归来看:①根节点要相等②左边的左子树和右边的右子树相等②左边的右子树和右边的左子树相等
  • 迭代来看:①左边看:左中右查看②右边看:右中左查看,对比值是否相等(和迭代中序遍历一样的思路)

递归版:

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def isSymmetric(self, root: TreeNode) -> bool:
        if not root:
            return True
        return self.dfs(root.left, root.right)
    
    def dfs(self, l, r):
        if not l or not r:
            return not l and not r
        return l.val == r.val and self.dfs(l.left, r.right) and self.dfs(l.right,r.left)

迭代版:

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def isSymmetric(self, root: TreeNode) -> bool:
        # 为空
        if not root:
            return True
        stack1, stack2 = [], []
        p, q = root.left, root.right
        while p or q or stack1 or stack2:
            while q and p:
                stack1.append(p)
                p = p.left
                stack2.append(q)
                q = q.right
            if p or q:
                return False
            p = stack1.pop()
            q = stack2.pop()
            if p.val != q.val:
                return False
            p = p.right
            q = q.left
        return True
        

105. 从前序与中序遍历序列构造二叉树

思路:

  • 这类题的思路其实差不多,以preorder = [3,9,20,15,7],inorder = [9,3,15,20,7]为例。preorder第一个出现的是根节点,找到其在inorder的位置p,则p左边是属于左子树,p右边属于右子树。递归的再在左子树、右子树的部分重复上述过程即可。
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
        # 存储数字在inorder中的下标
        pos = {}
        for index, num in enumerate(inorder):
            pos[num] = index
        # 二叉树节点个数
        n = len(preorder)
        return self.dfs(preorder, inorder, pos, 0, n-1, 0, n-1)
    
    def dfs(self, preorder, inorder, pos, pl, pr, il, ir):
        # 已经建立完
        if pl > pr:
            return
        # 取出根节点
        val = preorder[pl]
        # 获得在inorder中的下标
        p = pos[val]
        # 左子树个数
        len_ = p - il
        # 建立新节点
        root = TreeNode(val)
        root.left = self.dfs(preorder, inorder, pos, pl+1, pl+len_, il, p-1)
        root.right = self.dfs(preorder, inorder, pos, pl+len_+1, pr, p+1, ir)
        return root

102. 二叉树的层序遍历

思路:

  • BFS,以层为单位做
  • 注意python列表传递值的时候需要[:]
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        if not root:
            return []
        # 存储当前层的节点
        cur = [root]
        # 存储下一层的节点
        next_node = []
        # 存储当前层的结果
        cur_res = []
        # 存储最终结果
        res = []
        while cur:
            # 取出当前层的节点
            x = cur.pop(0)
            if x.left:# 有左孩子就放入下一层
                next_node.append(x.left)
            if x.right:# 有右孩子就放入下一层
                next_node.append(x.right)
            cur_res.append(x.val)
            # 当前层遍历完
            if not cur:
                cur = next_node[:]
                res.append(cur_res[:])
                next_node.clear()
                cur_res.clear()
        return res

            

236. 二叉树的最近公共祖先

思路:

  • 这是一个递归的思路,如果当前root为根的子树中包含了p和q,则返回最近共公共祖先
  • 如果只包含了p,则返回p
  • 如果只包含了q,则返回q
  • 如果都不包含则返回null
  • 如果p、q在异侧,返回root
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if not root or root==p or root==q:
            # 若根节点为空或者根节点就是p、q
            return root
        left = self.lowestCommonAncestor(root.left, p, q)
        right = self.lowestCommonAncestor(root.right, p, q)
        if not left:
            # p、q不在左子树中
            return right
        if not right:
            # p、q不在右子树中
            return left
        return root

543. 二叉树的直径

思路:

  • 二叉树的直径是指最长的路径
  • 枚举树中的所有最高点
  • 经过当前点的最长路径即其左子树的最长路径+右子树的最长路径
  • 递归时需要计算,从当前节点往下走,深度的最大值
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def __init__(self):
        self.res = 0
    
    def diameterOfBinaryTree(self, root: TreeNode) -> int:
        if not root:
            return 0
        self.dfs(root)
        return self.res
    
    def dfs(self, root):
        if not root:
            return 0
        left = self.dfs(root.left)
        right = self.dfs(root.right)
        self.res = max(self.res, left+right)
        return max(left, right)+1

124. 二叉树中的最大路径和

思路:

  • 枚举最高点
  • 向左走,当前val+L
  • 向右走,当前val+R
  • 不走
  • 三种情况取最大值,向上返回的时候,若是负值其实已经没有必要返回
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def __init__(self):
        self.res = -float('inf')

    def maxPathSum(self, root: TreeNode) -> int:
        self.dfs(root)
        return self.res
    
    def dfs(self, root):
        # 返回当前root向下走最大权值
        if not root:
            return 0
        left = self.dfs(root.left)
        right = self.dfs(root.right)
        self.res = max(self.res, left+right+root.val)
        return max(0, root.val+max(left, right))

173. 二叉搜索树迭代器

思路:

  • 由于是要使用O(h)的内存,所以是跟树高相关,若是直接进行一个中序遍历的话,则会使用O(n)的内存,即节点个数。所以首先考虑栈的方式。
  • 利用栈存储中序遍历的结果,栈顶就一直放的是最小的那个
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class BSTIterator:

    def __init__(self, root: TreeNode):
        self.stk = []
        p = root
        while p:
            self.stk.append(p)
            p = p.left

    def next(self) -> int:
        """
        @return the next smallest number
        """
        p = self.stk.pop()
        res = p.val
        p = p.right
        while p:
            self.stk.append(p)
            p = p.left
        
        return res



    def hasNext(self) -> bool:
        """
        @return whether we have a next smallest number
        """
        if self.stk:
            return True
        else:
            return False



# Your BSTIterator object will be instantiated and called as such:
# obj = BSTIterator(root)
# param_1 = obj.next()
# param_2 = obj.hasNext()

297. 二叉树的序列化与反序列化

思路:

  • 主要需要考虑如何序列化,并且反序列化如何处理。
  • 这里使用的是前序遍历序列化、反序列化
# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Codec:

    def serialize(self, root):
        """Encodes a tree to a single string.
        
        :type root: TreeNode
        :rtype: str
        """
        return self.dfs1(root, "")
    
    def dfs1(self, root, s):
        if not root:
            s += '#,'
        else:
            s += str(root.val) + ","
            s = self.dfs1(root.left, s)
            s = self.dfs1(root.right, s)
        return s
        

    def deserialize(self, data):
        """Decodes your encoded data to tree.
        
        :type data: str
        :rtype: TreeNode
        """
        li = data.split(",")
        return self.dfs2(li)
    
    def dfs2(self, li):
        if not li:
            return
        if li[0] == "#":
            li.pop(0)
            return None
        else:
            root = TreeNode(int(li[0]))
        li.pop(0)
        root.left = self.dfs2(li)
        root.right = self.dfs2(li)
        return root

# Your Codec object will be instantiated and called as such:
# codec = Codec()
# codec.deserialize(codec.serialize(root))

 

你可能感兴趣的:(学习,算法练习)