LeetCode 404:左叶子之和(Sum of Left Leaves)


文章目录

摘要

在日常开发中,树形结构是我们经常会碰到的一类数据,比如菜单结构、组织架构、文件系统、或者语法树。而在这些结构中,我们有时需要针对某些特定的节点做聚合计算,比如"求所有左叶子的值之和"。

这道题其实就是一个非常典型的树遍历与判断逻辑结合的题目。看似简单,但它考察了如何准确识别左叶子如何递归遍历树 以及如何在遍历中累加计算结果。本文我们就用 Swift 来带你一步步分析并实现这个题目。

描述

题目要求很清晰:

给定一棵二叉树的根节点 root,返回所有左叶子节点的值之和

左叶子指的是"父节点的左子节点",并且这个左子节点本身没有子节点(也就是它是叶子)。

举个例子

txt 复制代码
输入: root = [3,9,20,null,null,15,7] 
输出: 24 
解释: 左叶子是 9 和 15,它们的和是 24。

题解答案

解决这个问题其实很自然地想到递归。

我们可以从根节点出发,去看它的左右子节点:

  1. 如果左子节点存在,并且它是一个叶子,那么直接加上它的值。
  2. 如果不是叶子,就递归地去继续找。
  3. 右子节点同理,只不过我们不去累加它(因为右叶子不计入结果)。

题解代码分析

下面是完整的 Swift 代码实现,可直接在 Xcode 或 LeetCode Playground 中运行:

swift 复制代码
import Foundation

// 定义树节点结构
public class TreeNode {
    public var val: Int
    public var left: TreeNode?
    public var right: TreeNode?
    public init() { self.val = 0; self.left = nil; self.right = nil }
    public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil }
    public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) {
        self.val = val
        self.left = left
        self.right = right
    }
}

class Solution {
    func sumOfLeftLeaves(_ root: TreeNode?) -> Int {
        guard let node = root else { return 0 }
        
        var sum = 0
        
        // 判断当前节点的左子节点是否是叶子
        if let left = node.left {
            if left.left == nil && left.right == nil {
                sum += left.val
            } else {
                sum += sumOfLeftLeaves(left)
            }
        }
        
        // 右子树递归(但不直接加右叶子)
        if let right = node.right {
            sum += sumOfLeftLeaves(right)
        }
        
        return sum
    }
}

思路讲解:

  1. 递归出口:如果当前节点为空,直接返回 0。

  2. 左子树判断

    • 如果当前节点的左子树存在且是叶子(没有左右子节点),累加它的值。
    • 如果不是叶子,就递归地继续往下找左叶子。
  3. 右子树判断

    • 递归计算右子树中的左叶子之和(注意不是右叶子!)。
  4. 返回结果:不断回传计算结果,最终得到整个树的左叶子之和。

示例测试及结果

下面我们构建一个简单的示例二叉树,并测试一下上面的代码是否正确:

swift 复制代码
// 构造示例树
//     3
//    / \
//   9  20
//     /  \
//    15   7
let root = TreeNode(3)
root.left = TreeNode(9)
root.right = TreeNode(20, TreeNode(15), TreeNode(7))

let solution = Solution()
let result = solution.sumOfLeftLeaves(root)
print("左叶子之和为:\(result)")

输出结果:

txt 复制代码
左叶子之和为:24

一切正常,和题目示例一致

再测试一个边界情况:

swift 复制代码
let single = TreeNode(1)
print("单节点树左叶子之和:\(solution.sumOfLeftLeaves(single))")

输出:

txt 复制代码
单节点树左叶子之和:0

因为它没有左叶子,结果自然为 0。

时间复杂度

每个节点只会被访问一次,递归操作也都是常数时间判断。

因此时间复杂度是:

O(n) ------ 其中 n 是二叉树的节点总数。

空间复杂度

在递归过程中,系统栈的最大深度取决于树的高度。

最坏情况下(树退化为链表)为 O(n),平均情况约为 O(log n)。

因此:

空间复杂度:O(h),其中 h 是树的高度。

总结

这道题的核心不在于算法复杂度,而在于如何准确识别"左叶子"

我们要注意两个关键点:

  • 必须是左节点(不是右节点)
  • 必须是叶子节点(没有左右子节点)

整体思路非常自然,用递归最简洁,但如果在性能敏感的场景下,也可以用 BFS 或栈模拟递归实现迭代版。

在实际开发中,类似的"聚合型遍历问题"非常常见,比如:

  • 统计树中所有叶子节点的数量
  • 累加某种类型节点的值
  • 查找满足特定条件的节点路径

掌握这类递归模式,几乎可以解决 80% 的树结构算法题。

相关推荐
北域码匠3 小时前
SHA-1算法:安全哈希原理与应用解析
算法·c#·哈希算法
手写码匠4 小时前
手写 GraphRAG:从零实现图增强检索增强生成系统
人工智能·深度学习·算法·aigc
BomanGe14 小时前
NSK重载高刚性滚珠丝杠技术详解
经验分享·算法·规格说明书
Matrix_115 小时前
手机里的计算摄影:广角形变校正算法
人工智能·算法·智能手机·计算摄影
WBluuue5 小时前
数据结构与算法:有序表(二):跳表
数据结构·c++·算法·skiplist
IT龟苓膏5 小时前
并发深度解析】硬核手撕 ForkJoinPool + WorkStealing + CompletableFuture 底层源码与大厂面试演练
面试·职场和发展
x138702859576 小时前
c语言中srtlen(指针使用计算字符长度)、传值和传址调用
c语言·开发语言·算法·visual studio
海兰6 小时前
【实用程序】电商销售分析仪表盘 — 从零搭建一个AI参与的全栈数据洞察系统
人工智能·学习·算法
zwenqiyu7 小时前
P5283 [十二省联考 2019] 异或粽子题解
c++·学习·算法
wayz117 小时前
Momentum:TSI(真实强度指数)技术指标详解
算法·金融·数据分析·量化交易·特征工程