力扣250题:计算同值子树数量(Count Univalue Subtrees)

在本篇文章中,我们将详细解读力扣第250题"统计同值子树"。通过学习本篇文章,读者将掌握如何在二叉树中统计所有节点值相同的子树数量,并了解相关的复杂度分析和模拟面试问答。每种方法都将配以详细的解释,以便于理解。

问题描述

力扣第250题"统计同值子树"描述如下:

复制代码
给定一棵二叉树,统计其中节点值都相同的子树的数量。

示例:

解题思路

方法一:递归后序遍历

  1. 初步分析:

• 同值子树指的是子树中的所有节点值都相同。因此,我们可以从叶子节点开始递归地检查每棵子树是否是同值子树。

• 通过后序遍历,我们可以先检查左右子树是否是同值子树,然后判断当前子树是否是同值子树。

  1. 步骤:

• 使用一个全局变量 count 记录同值子树的数量。

• 定义一个递归函数 is_unival_subtree,返回当前子树是否是同值子树:

• 如果当前节点为空,返回 True(空树是同值子树)。

• 递归检查左右子树是否是同值子树。

• 如果当前节点与左右子树的根节点值不同,则当前子树不是同值子树。

• 如果当前节点的值与左右子树的值相同,则当前子树是同值子树,计数器加一。

• 最后返回计数器的值。

代码实现

class TreeNode:

def init (self, val=0, left=None, right=None):

self.val = val

self.left = left

self.right = right

def countUnivalSubtrees(root):

count = 0

复制代码
def is_unival_subtree(node):
    nonlocal count
    if not node:
        return True
    
    left_is_unival = is_unival_subtree(node.left)
    right_is_unival = is_unival_subtree(node.right)
    
    if not left_is_unival or not right_is_unival:
        return False
    
    if node.left and node.val != node.left.val:
        return False
    if node.right and node.val != node.right.val:
        return False
    
    count += 1
    return True

is_unival_subtree(root)
return count

测试案例

root = TreeNode(5, TreeNode(1, TreeNode(5), TreeNode(5)), TreeNode(5, None, TreeNode(5)))

print(countUnivalSubtrees(root)) # 输出: 4

复杂度分析

• 时间复杂度:O(n),其中 n 是树中的节点数量。每个节点只需访问一次。

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

模拟面试问答

问题 1:你能描述一下如何解决这个问题的思路吗?

回答:我们使用后序遍历的递归方法解决这个问题。从叶子节点开始检查左右子树是否是同值子树,然后判断当前子树是否是同值子树。如果当前节点值与左右子树的值相同,则当前子树是同值子树,计数器加一。

问题 2:为什么选择使用后序遍历来解决这个问题?

回答:后序遍历能够自然地从叶子节点开始递归检查子树的性质。通过先检查左右子树,我们可以在判断当前子树是否是同值子树时确保左右子树的结果已经确定。这种方式简洁且高效,适合处理树形结构的问题。

问题 3:你的算法的时间复杂度和空间复杂度是多少?

回答:时间复杂度为 O(n),因为我们需要访问每个节点一次。空间复杂度为 O(h),因为递归调用栈的深度等于树的高度,在最坏情况下为 O(n)(链式树)。

问题 4:在代码中如何处理边界情况?

回答:对于空树,代码通过检查节点是否为空返回 True,并且不会增加计数器。对于只有一个节点的树,代码会正确地识别为同值子树,计数器加一。

问题 5:你能解释一下递归函数在这个问题中的具体作用吗?

回答:递归函数 is_unival_subtree 用于判断当前子树是否是同值子树。通过递归调用左右子树的结果,我们可以逐层向上返回是否满足同值子树的条件,并在每次满足条件时增加计数器。

问题 6:在代码中如何确保返回的结果是正确的?

回答:通过逐步递归遍历每个节点,并在每次递归返回时检查是否满足同值子树的条件,确保计数器记录的结果是正确的。测试用例验证了代码在多种树结构下的正确性。

问题 7:你能举例说明在面试中如何回答优化问题吗?

回答:在面试中,如果被问到如何优化算法,我会首先分析当前算法的时间复杂度和空间复杂度。由于时间复杂度已经是 O(n),进一步优化的空间有限。可以讨论如何在极端情况下优化递归调用栈的深度,或者使用迭代的方法替代递归。

问题 8:如何验证代码的正确性?

回答:通过编写详细的测试用例,涵盖所有可能的树结构,如空树、只有一个节点的树、所有节点值相同的树等,确保每个测试用例的结果都符合预期。此外,还可以通过手工推演树的遍历过程,验证代码逻辑的正确性。

问题 9:你能解释一下解决"统计同值子树"问题的重要性吗?

回答:解决"统计同值子树"问题展示了对树形结构的递归遍历和性质判断的能力,尤其是在判断子树性质时的技巧。通过掌握这个问题的解决方法,可以提高对树形数据结构的理解,并为处理更复杂的树形问题打下基础。

问题 10:在处理大数据集时,算法的性能如何?

回答:由于算法的时间复杂度为 O(n),在处理大数据集时性能仍然良好。即使树中包含大量节点,算法也能在一次遍历中完成所有检查。空间复杂度为 O(h),对于高度较小的平衡树,内存使用也非常少。

总结

本文详细解读了力扣第250题"统计同值子树",通过使用后序遍历的递归方法高效地统计二叉树中的同值子树数量,并提供了详细的解释和模拟面试问答。希望读者通过本文的学习,能够在力扣刷题的过程中更加得心应手。

相关推荐
椰羊~王小美几秒前
贪心算法和动态规划
算法·贪心算法·动态规划
圣保罗的大教堂1 分钟前
leetcode 2302. 统计得分小于 K 的子数组数目 困难
leetcode
纪元A梦8 分钟前
华为OD机试真题——阿里巴巴找黄金宝箱Ⅰ(2025A卷:100分)Java/python/JavaScript/C/C++/GO最佳实现
java·c语言·javascript·c++·python·华为od·go
AI_RSER18 分钟前
Python 数据可视化全场景实现(一)
开发语言·人工智能·python·信息可视化·遥感
eqwaak021 分钟前
Matplotlib高阶技术全景解析(续):动态交互、三维可视化与性能优化
开发语言·python·语言模型·性能优化·交互·matplotlib
愚润求学25 分钟前
【专题四】前缀和(3)
开发语言·c++·笔记·leetcode·刷题·c++11
uhakadotcom27 分钟前
持续写作的“农耕思维”:如何像农民一样播种,收获稳定成长与收入
后端·面试·github
蜗牛沐雨28 分钟前
Pandas 数据导出:如何将 DataFrame 追加到 Excel 的不同工作表
python·excel·pandas
啊阿狸不会拉杆1 小时前
人工智能数学基础(二):初等数学
人工智能·python·算法
元亓亓亓1 小时前
LeetCode热题100--560.和为K的子数组(前缀和)--中等
算法·leetcode·职场和发展