二叉树 递归

本篇基于b站灵茶山艾府的课上例题与课后作业。

104. 二叉树的最大深度

给定一个二叉树 root ,返回其最大深度。

二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。

示例 1:

img

输入:root = [3,9,20,null,null,15,7]
输出:3

示例 2:

输入:root = [1,null,2]
输出: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 maxDepth(self, root: Optional[TreeNode]) -> int:
        # 方法1:自底向上(归)
        # def dfs(node):
        #     if node == None:
        #         return 0
        #     return max(dfs(node.left), dfs(node.right)) + 1

        # return dfs(root)

        # 方法2:自顶向下(递)
        ans = 0     

        def dfs(node, cnt):
            if node == None:
                return
            nonlocal ans
            ans = max(ans, cnt)
            dfs(node.left, cnt + 1)
            dfs(node.right, cnt + 1)

        dfs(root, 1)
        return ans


111. 二叉树的最小深度

给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

**说明:**叶子节点是指没有子节点的节点。

示例 1:

img

输入:root = [3,9,20,null,null,15,7]
输出:2

示例 2:

输入:root = [2,null,3,null,4,null,5,null,6]
输出: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
class Solution:
    def minDepth(self, root: Optional[TreeNode]) -> int:
        # # 最小深度是根节点到最近叶子节点的深度
        # 1.自底向上(归)
        # def dfs(node):
        #     # 递归边界
        #     if not node:
        #         return 0

        #     # 如果没有左孩子但是有右孩子,,说明当前不是叶子节点,还没有到递归边界,则变成右子树的最小深度的问题
        #     if not node.left:
        #         return dfs(node.right) + 1

        #     # 如果没有右孩子但是有左孩子,说明当前不是叶子节点,还没有到递归边界,变成左子树的最小深度的问题
        #     if not node.right:
        #         return dfs(node.left) + 1

        #     # 左右孩子都有,返回左子树的最小深度和右子树的最小深度加1
        #     return min(dfs(node.left), dfs(node.right)) + 1

        # return dfs(root)

        # 2.自顶向下(递)
        def dfs(node, cnt):
            nonlocal ans
            if node == None:
                return
            # 最优性剪枝:继续向下递归也不会让最小深度变小
            if cnt >= ans:
                return

            cnt += 1
            # 如果是叶子节点,则记录答案,并返回
            if not node.left and not node.right:
                ans = min(ans, cnt)
                return
            # 如果不是叶子节点,则继续往下递归
            dfs(node.left, cnt)
            dfs(node.right, cnt)

        ans = inf
        dfs(root, 0)
        return ans if ans != inf else 0


112. 路径总和

给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false

叶子节点 是指没有子节点的节点。

示例 1:

img

输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
输出:true
解释:等于目标和的根节点到叶节点路径如上图所示。

示例 2:

img

输入:root = [1,2,3], targetSum = 5
输出:false
解释:树中存在两条根节点到叶子节点的路径:
(1 --> 2): 和为 3
(1 --> 3): 和为 4
不存在 sum = 5 的根节点到叶子节点的路径。

示例 3:

输入:root = [], targetSum = 0
输出:false
解释:由于树是空的,所以不存在根节点到叶子节点的路径。

# 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 hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        def dfs(node, target):
            # 边界条件是空节点,如果一个节点是空,则没有0,一定凑不到target
            if not node:
                return False

            # 除空节点之外的节点可以分为非叶子节点和叶子节点
            target -= node.val
            # 如果是叶子节点
            if node.left == node.right:
                return target == 0
            # 如果是非叶子节点,继续往下递归
            return dfs(node.left, target) or dfs(node.right, target)

        return dfs(root, targetSum)


129. 求根节点到叶节点数字之和

给你一个二叉树的根节点 root ,树中每个节点都存放有一个 09 之间的数字。

每条从根节点到叶节点的路径都代表一个数字:

  • 例如,从根节点到叶节点的路径 1 -> 2 -> 3 表示数字 123

计算从根节点到叶节点生成的 所有数字之和

叶节点 是指没有子节点的节点。

示例 1:

img

输入:root = [1,2,3]
输出:25
解释:
从根到叶子节点路径 1->2 代表数字 12
从根到叶子节点路径 1->3 代表数字 13
因此,数字总和 = 12 + 13 = 25

示例 2:

img

输入:root = [4,9,0,5,1]
输出:1026
解释:
从根到叶子节点路径 4->9->5 代表数字 495
从根到叶子节点路径 4->9->1 代表数字 491
从根到叶子节点路径 4->0 代表数字 40
因此,数字总和 = 495 + 491 + 40 = 1026

# 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 sumNumbers(self, root: Optional[TreeNode]) -> int:
        # 1.有返回值写法
        # def dfs(node, s):
        #     # 边界条件是节点为空时,不可能有值,返回
        #     if not node:
        #         return
        #     nonlocal ans

        #     # 非边界的节点可以分为叶子节点和非叶子节点
        #     s += str(node.val)
        #     # 如果是叶子节点,记录答案
        #     if node.left == node.right:
        #         ans += int(s)
        #         return
        #     # 如果是非叶子节点,继续递归
        #     dfs(node.left, s)
        #     dfs(node.right, s)

        # ans = 0
        # dfs(root, "")
        # return ans

        # 2.无返回值写法
        def dfs(node, x):
            if not node:
                return 0

            x = x * 10 + node.val
            if node.left == node.right:
                return x

            return dfs(node.left, x) + dfs(node.right, x)

        return dfs(root, 0)


1448. 统计二叉树中好节点的数目

给你一棵根为 root 的二叉树,请你返回二叉树中好节点的数目。

「好节点」X 定义为:从根到该节点 X 所经过的节点中,没有任何节点的值大于 X 的值。

示例 1:

img

输入:root = [3,1,4,3,null,1,5]
输出:4
解释:图中蓝色节点为好节点。
根节点 (3) 永远是个好节点。
节点 4 -> (3,4) 是路径中的最大值。
节点 5 -> (3,4,5) 是路径中的最大值。
节点 3 -> (3,1,3) 是路径中的最大值。

示例 2:

img

输入:root = [3,3,null,4,2]
输出:3
解释:节点 2 -> (3, 3, 2) 不是好节点,因为 "3" 比它大。

示例 3:

输入:root = [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 goodNodes(self, root: Optional[TreeNode]) -> int:
        # 1.向下递
        # def dfs(node, mv):  # mv表示max_val,根节点(第一个节点)到当前节点路径的最大节点值
        #     if not node:
        #         return
        #     nonlocal ans
        #     # 如果当前节点值大于等于路径上其他节点值,则是一个好节点
        #     if node.val >= mv:
        #         ans += 1
        #     mv = max(mv, node.val)  # 更新这条路径上的最大节点值
        #     # 继续递归
        #     dfs(node.left, mv)
        #     dfs(node.right, mv)

        # ans = 0
        # dfs(root, -inf)
        # return ans

        # 2.向上归
        def dfs(node, mv):
            if not node:
                return 0
            mv = max(node.val, mv)
            
            if node.val >= mv:
                return dfs(node.left, mv) + dfs(node.right, mv) + 1
            return dfs(node.left, mv) + dfs(node.right, mv)

        return dfs(root, -inf)


987. 二叉树的垂序遍历

给你二叉树的根结点 root ,请你设计算法计算二叉树的 垂序遍历 序列。

对位于 (row, col) 的每个结点而言,其左右子结点分别位于 (row + 1, col - 1)(row + 1, col + 1) 。树的根结点位于 (0, 0)

二叉树的 垂序遍历 从最左边的列开始直到最右边的列结束,按列索引每一列上的所有结点,形成一个按出现位置从上到下排序的有序列表。如果同行同列上有多个结点,则按结点的值从小到大进行排序。

返回二叉树的 垂序遍历 序列。

示例 1:

img

输入:root = [3,9,20,null,null,15,7]
输出:[[9],[3,15],[20],[7]]
解释:
列 -1 :只有结点 9 在此列中。
列  0 :只有结点 3 和 15 在此列中,按从上到下顺序。
列  1 :只有结点 20 在此列中。
列  2 :只有结点 7 在此列中。

示例 2:

img

输入:root = [1,2,3,4,5,6,7]
输出:[[4],[2],[1,5,6],[3],[7]]
解释:
列 -2 :只有结点 4 在此列中。
列 -1 :只有结点 2 在此列中。
列  0 :结点 1 、5 和 6 都在此列中。
          1 在上面,所以它出现在前面。
          5 和 6 位置都是 (2, 0) ,所以按值从小到大排序,5 在 6 的前面。
列  1 :只有结点 3 在此列中。
列  2 :只有结点 7 在此列中。

示例 3:

img

输入:root = [1,2,3,4,6,5,7]
输出:[[4],[2],[1,5,6],[3],[7]]
解释:
这个示例实际上与示例 2 完全相同,只是结点 5 和 6 在树中的位置发生了交换。
因为 5 和 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
class Solution:
    def verticalTraversal(self, root: Optional[TreeNode]) -> List[List[int]]:
        from collections import defaultdict
        #哈希表,键为节点所在的列,值为(行,值)
        li = defaultdict(list)

        def dfs(root, i, j):
            if root == None:
                return
            li[j].append((i, root.val))
            dfs(root.left, i + 1, j - 1)
            dfs(root.right, i + 1, j + 1)

        dfs(root, 0, 0)
        res = []
        # sorted(li.items()):给哈希表中按键排序
        for key, values in sorted(li.items()):
            # 给值里面的列表排序,列表里面为元组,排序依据为元组的第一个值,再第二个值
            values.sort()
            res.append([i[1] for i in values])
        return res
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

noruta

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值