【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<min_val:
            return False
        return self.dfs(root.left, min_val, root.val-1) and self.dfs(root.right, root.val+1, max_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))

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章