✅DAY15 二叉树续 | 222.完全二叉树的节点个数 | 110.平衡二叉树 | 257. 二叉树的所有路径 | 404.左叶子之和 | 222.完全二叉树的节点个数

222.完全二叉树的节点个数

解题思路:用后序解题

class Solution:
    def countNodes(self, root: Optional[TreeNode]) -> int:
        if not root:
            return 0
        # 左 右 中
        leftCount = self.countNodes(root.left)
        rightCount = self.countNodes(root.right)
        return leftCount + rightCount + 1

解题思路:利用完全二叉树的原理去解答

class Solution:
    def countNodes(self, root: Optional[TreeNode]) -> int:
        if not root:
            return 0
        # 给定完全二叉树--> 从上到下找满二叉树(2^n - 1) + 子树个数 
        # 如果左侧深度==右侧深度,这是个满二叉树
        leftNode = root.left
        rightNode = root.right
        leftDepth, rightDepth =0,0
        while leftNode:
            leftNode = leftNode.left
            leftDepth +=1
        while rightNode:
            rightNode = rightNode.right
            rightDepth += 1
        #如果左侧深度等于右侧深度,则整个子树是一个满二叉树。
        #在这种情况下,节点总数为 2^(leftDepth + 1) - 1
        if leftDepth == rightDepth:
            return 2**(leftDepth+1) - 1

        return 1 + self.countNodes(root.left) + self.countNodes(root.right)

110.平衡二叉树

题目:左右子树高度差<=1

解题思路:递归的办法

1. isBalanced 方法

        • 直接调用 getHeight 方法,如果返回值为 -1,表示树不平衡;否则树平衡。

2. getHeight 方法(递归获取子树高度,并检查平衡性):

        • 终止条件:如果 node 为 None,返回高度 0。

        • 递归获取左右子树高度

        • leftHeight 是左子树的高度。如果返回 -1,表示左子树已经不平衡,直接返回 -1。

        • rightHeight 是右子树的高度。如果返回 -1,表示右子树已经不平衡,直接返回 -1。

检查平衡性

        • 如果左右子树高度差超过 1,返回 -1 表示不平衡。

返回节点高度

        • 如果左右子树平衡,则返回 1 + max(leftHeight, rightHeight),表示当前节点的高度。

时间复杂度:O(n),因为每个节点只访问一次。

空间复杂度:O(h),其中 h 是树的高度,用于递归调用栈。

class Solution:
    def isBalanced(self, root: Optional[TreeNode]) -> bool:
        return self.getHeight(root) != -1

    def getHeight(self,node):
        if not node: return 0

        leftHeight = self.getHeight(node.left)
        if leftHeight == -1: return -1

        rightHeight = self.getHeight(node.right)
        if rightHeight == -1: return -1
        
        if abs(rightHeight - leftHeight) > 1 : return -1

        return 1 + max(rightHeight, leftHeight) 

解题思路:迭代。用一个栈 stack 存储节点和它的访问状态,每个元素是一个 (node, visited) 元组。visited 标记是否已经处理过该节点的左右子树。

class Solution:
    def isBalanced(self, root: Optional[TreeNode]) -> bool:
        if not root:
            return True
        
        # 栈存储元组 (节点, 是否已访问)
        stack = [(root, False)]
        # 字典存储每个节点的高度
        height = {None: 0}
        
        while stack:
            node, visited = stack.pop()
            
            if node is None:
                continue
            
            if visited:
                # 已经访问过该节点,计算该节点的高度
                leftHeight = height[node.left]
                rightHeight = height[node.right]
                
                # 如果左右子树高度差超过 1,返回 False
                if abs(leftHeight - rightHeight) > 1:
                    return False
                
                # 记录该节点的高度
                height[node] = 1 + max(leftHeight, rightHeight)
            else:
                # 第一次遇到该节点,将其标记为已访问
                stack.append((node, True))
                # 先加入右子节点,再加入左子节点
                stack.append((node.right, False))
                stack.append((node.left, False))
        
        return True

257. 二叉树的所有路径

解题思路:使用递归遍历二叉树的所有路径,path 列表用于记录当前路径,result 列表用于存储所有完整路径。

叶节点处理:如果当前节点没有左子树和右子树(是叶节点),将 path 转换为路径字符串并添加到 result 中。

回溯:path.pop() 在递归调用完成后执行,确保每条路径都能恢复到上一级状态,以便不影响其他路径。

class Solution:
    def binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]:
        result = []
        path = []
        if not root: 
            return result
        self.traversal(root, path, result)
        return result
        
    def traversal(self, node, path, result):
        path.append(node.val)
        
        # 如果当前节点是叶子节点,将路径加入结果中
        if not node.left and not node.right:
            sPath = '->'.join(map(str, path))
            result.append(sPath)
        
        # 如果存在左子树,继续遍历左子树
        if node.left:
            self.traversal(node.left, path, result)
        
        # 如果存在右子树,继续遍历右子树
        if node.right:
            self.traversal(node.right, path, result)
        
        # 回溯,弹出当前节点,恢复上一层的路径
        path.pop()

隐藏回溯:递归调用时传入 path[:](即 path 的切片副本)来实现“隐藏”回溯。使用 path[:] 会生成一个新的列表副本,因此每次递归调用时修改 path 不会影响原始的 path 列表,从而实现了不需要显式回溯的效果。

from typing import List, Optional

class Solution:
    def binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]:
        if not root:
            return []
        result = []
        self.traversal(root, [], result)
        return result
    
    def traversal(self, cur: TreeNode, path: List[int], result: List[str]) -> None:
        if not cur:
            return
        path.append(cur.val)
        
        # 如果是叶子节点,加入结果
        if not cur.left and not cur.right:
            result.append('->'.join(map(str, path)))
        
        # 递归遍历左子树和右子树,传入 path 的副本
        if cur.left:
            self.traversal(cur.left, path[:], result)
        if cur.right:
            self.traversal(cur.right, path[:], result)

404.左叶子之和

class Solution:
    def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
        if not root: 
            return 0

        # 递归调用左子树
        leftValue = self.sumOfLeftLeaves(root.left)
        
        # 检查当前节点的左子节点是否为叶子节点
        if root.left and not root.left.left and not root.left.right:
            leftValue += root.left.val
        
        # 递归调用右子树
        rightValue = self.sumOfLeftLeaves(root.right)

        return leftValue + rightValue
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值