二叉树专题

文章介绍了多个与二叉树相关的算法问题,包括在二叉搜索树中找到第K小的元素、有序数组和链表转换为二叉搜索树、判断平衡二叉树、计算最小深度、路径总和以及填充每个节点的下一个右侧节点指针。解决方案主要基于深度优先搜索和二叉搜索树的特性进行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

230. 二叉搜索树中第K小的元素(🎂)

class Solution:
    def kthSmallest(self, root: Optional[TreeNode], k: int) -> int:
        # 二叉搜索树中序遍历的结果是一个递增序列,所以使用dfs,直接中序遍历k次即可
        self.ans = 0
        self.cnt = 0
        def dfs(root):
            if not root: return 
            dfs(root.left)
            self.cnt += 1
            if k == self.cnt: 
                self.ans = root.val
                return
            dfs(root.right)

        dfs(root)
        return self.ans

108. 将有序数组转换为二叉搜索树(🎂)

class Solution:
    def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
        # 每次选nums的中位数来作为根节点
        # n = len(nums)
        # root = TreeNode(nums[n // 2])
        def dfs(nums):
            if not nums: return None
            if len(nums) == 1: 
                return TreeNode(nums[0])
            n = len(nums)
            node = TreeNode(nums[n // 2])
            node.left = dfs(nums[:n // 2])
            node.right = dfs(nums[n // 2 + 1:])
            
            return node
        
        return dfs(nums)

109. 有序链表转换二叉搜索树(🎂)

笨方法是先吧链表转化成有序数组,之后就是108题一模一样了。但是这么做肯定不是最优解,但是时间复杂度应该是很低了。

class Solution:
    def sortedListToBST(self, head: Optional[ListNode]) -> Optional[TreeNode]:
        # 最笨的方法,先将链表转化成数组
        nums = []
        while head:
            nums.append(head.val)
            head = head.next
        # 之后按照有序数组转二叉搜索树的方法转就可以了
        def dfs(nums):
            if not nums: return 
            if len(nums) == 1: return TreeNode(nums[0])
            n = len(nums)

            node = TreeNode(nums[n // 2])
            node.left = dfs(nums[:n // 2])
            node.right = dfs(nums[n // 2 + 1:])
            return node
        
        return dfs(nums)
        

110. 平衡二叉树

# 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 isBalanced(self, root: Optional[TreeNode]) -> bool:
        if not root: return True
        return abs(self.height(root.left) - self.height(root.right)) <= 1 and self.isBalanced(root.left) and self.isBalanced(root.right)
        
    def height(self, root):
        if not root: return 0
        return max(self.height(root.left), self.height(root.right)) + 1

111. 二叉树的最小深度

# 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 minDepth(self, root: Optional[TreeNode]) -> int:
        if not root: return 0
        def recur(root):
            if not root: return float('inf')
            if not root.left and not root.right: return 1
            return min(recur(root.left), recur(root.right)) + 1
        
        return recur(root)
class Solution:
    def minDepth(self, root: Optional[TreeNode]) -> int:
        if not root: return 0
        if not root.left and not root.right: return 1

        # 如果一个节点缺失了左子节点或者右子节点,那么不会递归进入缺失子树
        min_depth = 10**9 + 1 # 给最小深度初始化一个很大的数
        if root.left:
            min_depth = min(self.minDepth(root.left), min_depth)
        if root.right:
            min_depth = min(self.minDepth(root.right), min_depth)
        
        return min_depth + 1

112. 路径总和

class Solution:
    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        if not root:
            return False

        def dfs(root, target):
            if not root: return False
            if not root.left and not root.right and target == root.val: return True

            left = dfs(root.left, target - root.val)
            right = dfs(root.right, target - root.val)
            return left or right
        
        return dfs(root, targetSum)
class Solution:
    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        if not root: return False
        if not root.left and not root.right and targetSum == root.val: return True

        return self.hasPathSum(root.left, targetSum - root.val) or self.hasPathSum(root.right, targetSum - root.val)

113. 路径总和 II

class Solution:
    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
        paths, path = [], []
        
        def dfs(root, target):
            if not root: return
            path.append(root.val)
            target = target - root.val
            if not root.left and not root.right and target == 0: 
                paths.append(path[:])
                # 为啥那么这里不直接return呢?按道理说应该有一个return,但是加上去之后结果不对了
                # return
            dfs(root.left, target)
            dfs(root.right, target)
            # target += root.val
            path.pop() # 虽然上面递归了两次,但是只需要pop一次

        dfs(root, targetSum)
        return paths

上面的代码其实不是很好理解,因为安扎去哦正常的回溯,满足条件之后可以直接return,但是官方解答中上面的代码为了优雅一些可能,多走了下面连个dfs两次,所以造成了很多人误解。

class Solution:
    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
        paths, path = [], []
        
        def dfs(root, target):
            if not root: return
            if not root.left and not root.right and target == root.val: 
                paths.append(path[:] + [root.val])
                return
            
            path.append(root.val)
            target -= root.val
            dfs(root.left, target)
            dfs(root.right, target)
            # target += root.val # 加不加这一句不影响
            path.pop()

        dfs(root, targetSum)
        return paths

116. 填充每个节点的下一个右侧节点指针

class Solution:
    def connect(self, root: 'Optional[Node]') -> 'Optional[Node]':
        if not root: return root
        stack = [root]
        while stack:
            n = len(stack) 
            for i in range(n):
                node = stack.pop(0)
                if i < n - 1:
                    node.next = stack[0]
                
                if node.left: stack.append(node.left)
                if node.right: stack.append(node.right)
        return root

117. 填充每个节点的下一个右侧节点指针 II

class Solution:
    def connect(self, root: 'Node') -> 'Node':
        if not root: return root
        stack = [root]
        while stack:
            n = len(stack)
            for i in range(n):
                node = stack.pop(0)
                if i < n - 1:
                    node.next = stack[0]
                if node.left: stack.append(node.left)
                if node.right: stack.append(node.right)
        
        return root

BFS版本上面两道题代码一模一样

235. 二叉搜索树的最近公共祖先(🎂)

要充分利用二叉搜索树的特性。

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        # 二叉搜索树的好处是可以根据p,q以及当前节点的值来判断在左右子树中搜索p还是q
        if not root: return
        # 当前节点就是最近的祖先
        if root.val == p.val or root.val == q.val: return root
        # 分散在两边
        if p.val < root.val < q.val: return root
        if q.val < root.val < p.val: return root
        # 聚集在一边
        if max(p.val, q.val) < root.val:
            return self.lowestCommonAncestor(root.left, p, q)
        elif max(p.val, q.val) > root.val:
            return self.lowestCommonAncestor(root.right, p, q)
        

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

这个就完全没有任何的规律,只有不断地试。

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if not root: return
        # 当前节点就是最近的祖先
        if root.val == p.val or root.val == q.val: return root
        left = self.lowestCommonAncestor(root.left, p, q)
        right = self.lowestCommonAncestor(root.right, p, q)
        if left and right: return root # 分散在两边
        # 这里不能使用这种判断是因为,return root左右都为空的时候,还是会返回root,这个时候应该返回None。所以最后改成return 就可以了
        # if left: return left # 聚集在左边
        # if right: return right # 聚集在右边
        if not left: return right # 左边没有,那就是右边
        if not right: return left # 右边没有,那就是左边
        return root # 左右都没有,那就是找不到

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if not root: return root
        # 当前节点就是最近的祖先
        if root.val == p.val or root.val == q.val: return root
        left = self.lowestCommonAncestor(root.left, p, q)
        right = self.lowestCommonAncestor(root.right, p, q)
        if left and right: return root # 分散在两边
        
        return left if left else right

剑指 Offer II 054. 所有大于等于节点的值之和(🎂)

要使用逆向的中序遍历

class Solution:
    def convertBST(self, root: TreeNode) -> TreeNode:
        # 因为要找比该节点大的所有节点,所以应该使用逆序的中序遍历
        self.sum = 0
        def inorder(root):
            if not root: return 0
            inorder(root.right)
            root.val = root.val + self.sum
            self.sum = root.val
            inorder(root.left)
            return 
        
        inorder(root)
        return root
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值