LeetCode题目100:递归、迭代、dfs使用栈多种算法图解相同的树

简介: LeetCode题目100:递归、迭代、dfs使用栈多种算法图解相同的树

作者介绍:10年大厂数据\经营分析经验,现任大厂数据部门负责人。

会一些的技术:数据分析、算法、SQL、大数据相关、python

欢迎加入社区:码上找工作

作者专栏每日更新:

LeetCode解锁1000题: 打怪升级之旅

python数据分析可视化:企业实战案例

python源码解读

程序员必备的数学知识与应用

备注说明:方便大家阅读,统一使用python,带必要注释,公众号 数据分析螺丝钉 一起打怪升级

题目描述

给定两个二叉树的根节点 pq,编写一个函数来检测这两棵树是否相同。如果两棵树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

示例

示例 1

输入:p = [1,2,3], q = [1,2,3]

输出:True

示例 2

输入:p = [1,2], q = [1,null,2]

输出:False


方法一:递归比较

解题步骤
  1. 基本情况:如果两个节点都是 None,返回 True。如果一个是 None 另一个不是,返回 False
  2. 值比较:如果当前两个节点的值不同,返回 False
  3. 递归比较:递归比较左子树和右子树。
Python 示例
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right
def isSameTree(p, q):
    """
    递归比较两棵树是否相同
    :param p: TreeNode, 第一棵树的根节点
    :param q: TreeNode, 第二棵树的根节点
    :return: bool, 两棵树是否相同
    """
    if not p and not q:
        return True
    if not p or not q:
        return False
    if p.val != q.val:
        return False
    return isSameTree(p.left, q.left) and isSameTree(p.right, q.right)
# 示例调用
p = TreeNode(1, TreeNode(2), TreeNode(3))
q = TreeNode(1, TreeNode(2), TreeNode(3))
print(isSameTree(p, q))  # 输出: True
算法分析
  • 时间复杂度:(O(n)),其中 (n) 是树中节点的数量,因为需要访问树中的每一个节点。
  • 空间复杂度:(O(h)),其中 (h) 是树的高度,空间消耗来自递归的栈空间。
ASCII 图解过程
[开始比较根节点]
  [1 == 1] -> True
    |---[左子树比较]
    |     [2 == 2] -> True
    |       |--[左子树比较] -> [null == null] -> True
    |       |--[右子树比较] -> [null == null] -> True
    |
    |---[右子树比较]
          [3 == 3] -> True
          |--[左子树比较] -> [null == null] -> True
          |--[右子树比较] -> [null == null] -> True
[树结构完全匹配] -> True

方法二:迭代使用队列

解题步骤
  1. 初始化队列:将根节点的对 (p, q) 加入队列。
  2. 迭代处理:从队列中取出节点对,比较这两个节点。如果不相同,则返回 False。如果相同,将他们的左孩子和右孩子按对加入队列。
  3. 重复:重复这个过程,直到队列为空。
Python 示例
from collections import deque
def isSameTree(p, q):
    """
    迭代使用队列比较两棵树是否相同
    :param p: TreeNode, 第一棵树的根节点
    :param q: TreeNode, 第二棵树的根节点
    :return: bool, 两棵树是否相同
    """
    queue = deque([(p, q)])
    while queue:
        p, q = queue.popleft()
        if not p and not q:
            continue
        if not p or not q:
            return False
        if p.val != q.val:
            return False
        queue.append((p.left, q.left))
        queue.append((p.right, q.right))
    return True
# 示例调用
p = TreeNode(1, TreeNode(2), TreeNode(3))
q = TreeNode(1, TreeNode(2), TreeNode(3))
print(isSameTree(p, q))  # 输出: True
算法分析
  • 时间复杂度:(O(n))
  • 空间复杂度:(O(n)),在最坏的情况下,如果树完全不平衡,队列可能需要存储所有节点。
ASCII 图解过程
[初始化队列] -> [(1, 1)]
  |--[比较节点 1 和 1] -> True
  |   |--[加入子节点对] -> [(2, 2), (3, 3)]
  |
  |--[比较节点 2 和 2] -> True
  |   |--[子节点都是 null,跳过]
  |
  |--[比较节点 3 和 3] -> True
      |--[子节点都是 null,跳过]
[队列空,结束] -> True

方法三:DFS 使用栈

解题步骤
  1. 使用栈模拟递归:将节点对压入栈中。
  2. 迭代比较:从栈中弹出节点对,进行比较。如果不相同,则返回 False。如果相同,将他们的左孩子和右孩子按对压入栈。
  3. 重复:直到栈为空。
Python 示例
def isSameTree(p, q):
    """
    使用栈实现深度优先搜索比较两棵树是否相同
    :param p: TreeNode, 第一棵树的根节点
    :param q: TreeNode, 第二棵树的根节点
    :return: bool, 两棵树是否相同
    """
    stack = [(p, q)]
    while stack:
        p, q = stack.pop()
        if not p and not q:
            continue
        if not p or not q or p.val != q.val:
            return False
        stack.append((p.right, q.right))
        stack.append((p.left, q.left))
    return True
# 示例调用
p = TreeNode(1, TreeNode(2), TreeNode(3))
q = TreeNode(1, TreeNode(2), TreeNode(3))
print(isSameTree(p, q))  # 输出: True
算法分析
  • 时间复杂度:(O(n))
  • 空间复杂度:(O(h)),其中 (h) 是树的高度,因为栈的最大深度由树的高度决定。
ASCII 图解过程
[初始化栈] -> [(1, 1)]
  |--[弹出节点 1 和 1] -> True
  |   |--[压入子节点对] -> [(3, 3), (2, 2)]
  |
  |--[弹出节点 2 和 2] -> True
  |   |--[子节点都是 null,跳过]
  |
  |--[弹出节点 3 和 3] -> True
      |--[子节点都是 null,跳过]
[栈空,结束] -> True

总结

这些方法提供了不同的方式来解决确定两棵树是否相同的问题。递归方法直观且易于实现,而迭代方法则在某些情况下可以提供更好的空间效率。选择哪种方法取决于具体情况和个人偏好。这些方法不仅可以应用于算法和数据结构的学习,还可以在实际开发中用于测试框架中验证复杂算法的输出结果或进行自动化测试。


欢迎关注微信公众号 数据分析螺丝钉

相关文章
|
19天前
|
分布式计算 算法 Go
【LeetCode 热题100】BFS/DFS 实战:岛屿数量 & 腐烂的橘子(力扣200 / 994 )(Go语言版)
本文讲解了两道经典的图论问题:**岛屿数量(LeetCode 200)** 和 **腐烂的橘子(LeetCode 994)**,分别通过 DFS/BFS 实现。在“岛屿数量”中,利用深度或广度优先搜索遍历二维网格,标记连通陆地并计数;“腐烂的橘子”则采用多源 BFS,模拟腐烂传播过程,计算最短时间。两者均需掌握访问标记技巧,是学习网格搜索算法的绝佳实践。
48 1
|
19天前
|
Go
【LeetCode 热题100】BFS/DFS 实战:岛屿数量 & 腐烂的橘子(力扣200 / 994 )(Go语言版)
本篇博客详细解析了三道经典的动态规划问题:198. 打家劫舍(线性状态转移)、279. 完全平方数与322. 零钱兑换(完全背包问题)。通过 Go 语言实现,帮助读者掌握动态规划的核心思想及其实战技巧。从状态定义到转移方程,逐步剖析每道题的解法,并总结其异同点,助力解决更复杂的 DP 问题。适合初学者深入理解动态规划的应用场景和优化方法。
35 0
|
3月前
|
资源调度 算法 数据可视化
基于IEKF迭代扩展卡尔曼滤波算法的数据跟踪matlab仿真,对比EKF和UKF
本项目基于MATLAB2022A实现IEKF迭代扩展卡尔曼滤波算法的数据跟踪仿真,对比EKF和UKF的性能。通过仿真输出误差收敛曲线和误差协方差收敛曲线,展示三种滤波器的精度差异。核心程序包括数据处理、误差计算及可视化展示。IEKF通过多次迭代线性化过程,增强非线性处理能力;UKF避免线性化,使用sigma点直接处理非线性问题;EKF则通过一次线性化简化处理。
157 14
|
8月前
|
算法
Leetcode 初级算法 --- 数组篇
Leetcode 初级算法 --- 数组篇
86 0
|
7月前
|
存储 算法 Java
leetcode算法题-有效的括号(简单)
【11月更文挑战第5天】本文介绍了 LeetCode 上“有效的括号”这道题的解法。题目要求判断一个只包含括号字符的字符串是否有效。有效字符串需满足左括号必须用相同类型的右括号闭合,并且左括号必须以正确的顺序闭合。解题思路是使用栈数据结构,遍历字符串时将左括号压入栈中,遇到右括号时检查栈顶元素是否匹配。最后根据栈是否为空来判断字符串中的括号是否有效。示例代码包括 Python 和 Java 版本。
147 4
|
8月前
|
程序员 C语言
【C语言】LeetCode(力扣)上经典题目
【C语言】LeetCode(力扣)上经典题目
141 1
|
10月前
|
算法
测试工程师的技能升级:LeetCode算法挑战与职业成长
这篇文章通过作者亲身体验LeetCode算法题的过程,探讨了测试工程师学习算法的重要性,并强调了算法技能对于测试职业成长的必要性。
141 1
测试工程师的技能升级:LeetCode算法挑战与职业成长
|
9月前
|
资源调度 算法
基于迭代扩展卡尔曼滤波算法的倒立摆控制系统matlab仿真
本课题研究基于迭代扩展卡尔曼滤波算法的倒立摆控制系统,并对比UKF、EKF、迭代UKF和迭代EKF的控制效果。倒立摆作为典型的非线性系统,适用于评估不同滤波方法的性能。UKF采用无迹变换逼近非线性函数,避免了EKF中的截断误差;EKF则通过泰勒级数展开近似非线性函数;迭代EKF和迭代UKF通过多次迭代提高状态估计精度。系统使用MATLAB 2022a进行仿真和分析,结果显示UKF和迭代UKF在非线性强的系统中表现更佳,但计算复杂度较高;EKF和迭代EKF则更适合维数较高或计算受限的场景。
|
9月前
|
SQL Oracle 关系型数据库
CASE WHEN 语句的语法及示例,LeetCode 题目 “确认率” 练习
本文介绍了SQL中CASE语句的两种形式和语法,并通过LeetCode题目“确认率”的SQL查询示例展示了CASE语句在实际问题中的应用,解释了如何使用CASE语句计算特定条件的比率。