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% 的树结构算法题。

相关推荐
想要打 Acm 的小周同学呀19 分钟前
爬虫相关的面试问题
爬虫·selenium·职场和发展
yongui4783437 分钟前
基于深度随机森林(Deep Forest)的分类算法实现
算法·随机森林·分类
是苏浙1 小时前
零基础入门C语言之C语言实现数据结构之单链表经典算法
c语言·开发语言·数据结构·算法
橘颂TA1 小时前
【剑斩OFFER】算法的暴力美学——点名
数据结构·算法·leetcode·c/c++
MATLAB代码顾问2 小时前
多种时间序列预测算法的MATLAB实现
开发语言·算法·matlab
PPT百科3 小时前
PPT插入的音乐怎么让它播放到某一页就停?
大数据·职场和发展·powerpoint·职场·ppt模板
m0_736927043 小时前
2025高频Java后端场景题汇总(全年汇总版)
java·开发语言·经验分享·后端·面试·职场和发展·跳槽
高山上有一只小老虎4 小时前
字符串字符匹配
java·算法
愚润求学4 小时前
【动态规划】专题完结,题单汇总
算法·leetcode·动态规划
林太白4 小时前
跟着TRAE SOLO学习两大搜索
前端·算法