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

相关推荐
南枝异客5 小时前
查找算法-顺序查找
python·算法
QuantumLeap丶5 小时前
《数据结构:从0到1》-06-单链表&双链表
数据结构·算法
李牧九丶6 小时前
从零学算法59
算法
一匹电信狗6 小时前
【C++】手搓AVL树
服务器·c++·算法·leetcode·小程序·stl·visual studio
月疯6 小时前
离散卷积,小demo(小波信号分析)
算法
敲代码的瓦龙7 小时前
西邮移动应用开发实验室2025年二面题解
开发语言·c++·算法
RTC老炮7 小时前
webrtc弱网-RembThrottler类源码分析及算法原理
网络·算法·webrtc
野蛮人6号7 小时前
力扣热题100道之73矩阵置零
算法·leetcode·矩阵
野蛮人6号7 小时前
力扣热题100道之238除自身以外数组的乘积
算法·leetcode·职场和发展