二叉树子树判断:从递归到迭代的全方位解析

一、题目解析

题目描述

给定两棵二叉树rootsubRoot,判断root中是否存在一棵子树,其结构和节点值与subRoot完全相同。

示例说明

  • 示例1
    root = [3,4,5,1,2]subRoot = [4,1,2]
    返回true,因为root的左子树与subRoot完全相同。

  • 示例2
    root = [3,4,5,1,2,null,null,null,null,0]subRoot = [4,1,2]
    返回false,虽然root存在节点值为4、1、2的路径,但结构与subRoot不同。

核心难点

  1. 如何高效遍历主树,找到可能与子树匹配的起始节点?
  2. 如何精确判断两棵树是否完全相同,避免结构或值的差异?

二、递归解法:深度优先搜索

核心思路

  1. 递归遍历主树:对主树的每个节点,检查以该节点为根的子树是否与目标子树相同。
  2. 递归判断子树是否相同:同时遍历两棵树的对应节点,确保结构和值完全一致。

代码实现

class Solution {public boolean isSubtree(TreeNode root, TreeNode subRoot) {return bfs(root,subRoot);}public boolean bfs(TreeNode root, TreeNode subRoot){if(root == null){return false;}return check(root,subRoot) || bfs(root.left,subRoot) || bfs(root.right,subRoot);}public boolean check(TreeNode root, TreeNode subRoot){if(root == null && subRoot == null){return true;}if(root == null || subRoot == null || root.val != subRoot.val){return false;}return check(root.left,subRoot.left) && check(root.right,subRoot.right);}
}

代码解析

  1. 主方法 isSubtree
    调用bfs方法开始递归遍历主树。

  2. 递归遍历方法 bfs

    • 终止条件:若主树为空,返回false
    • 检查当前节点:调用check方法判断以当前节点为根的子树是否与目标子树相同。
    • 递归搜索左右子树:只要在任一子树中找到匹配,立即返回true
  3. 子树比较方法 check

    • 终止条件:若两节点均为空,返回true;若仅一者为空或值不同,返回false
    • 递归比较:递归检查左右子树是否完全相同。

三、迭代解法:双端队列层序遍历

核心思路

  1. 层序遍历主树:使用双端队列按层遍历主树的每个节点。
  2. 检查子树是否相同:对每个节点,使用另一个双端队列同步比较其与目标子树的结构和值。

代码实现

class Solution {public boolean isSubtree(TreeNode root, TreeNode subRoot) {Deque<TreeNode> cur = new LinkedList<>();if (subRoot == null) return true;  if (root == null) return false;   TreeNode tempRoot = root;cur.offer(tempRoot);while(!cur.isEmpty()){tempRoot = cur.pollFirst();if(isSameTree(tempRoot,subRoot)){return true;}if(tempRoot.left != null){cur.offerFirst(tempRoot.left);}if(tempRoot.right != null){cur.offerFirst(tempRoot.right);}}return false;}public boolean isSameTree(TreeNode root, TreeNode subRoot) {Deque<TreeNode> cur = new LinkedList<>();if (root == null && subRoot == null) {return true;}TreeNode tempRoot = root;TreeNode tempSubRoot = subRoot;cur.offerFirst(tempRoot);cur.offerLast(tempSubRoot);while (!cur.isEmpty()) {tempRoot = cur.pollFirst();tempSubRoot = cur.pollLast();if (tempRoot == null && tempSubRoot == null) {continue;}if (tempRoot == null || tempSubRoot == null || tempSubRoot.val != tempRoot.val) {return false;}cur.offerFirst(tempRoot.left);cur.offerFirst(tempRoot.right);cur.offerLast(tempSubRoot.left);cur.offerLast(tempSubRoot.right);}return true;}
}

代码解析

  1. 主方法 isSubtree

    • 初始化队列:将主树根节点入队。
    • 层序遍历:每次从队列取出节点,调用isSameTree检查是否匹配。
    • 扩展队列:将当前节点的左右子节点入队,继续遍历。
  2. 子树比较方法 isSameTree

    • 双队列同步遍历:使用双端队列分别存储主树和子树的节点。
    • 节点比较:每次从队列取出两个节点,检查是否结构和值相同,并将其子节点入队。
    • 入队策略:主树节点从队首入队,子树节点从队尾入队,确保对应节点同步比较。

四、寻找匹配节点的关键逻辑

递归法

  • 遍历策略:采用前序遍历(根→左→右),确保每个节点都被检查。
  • 匹配条件:当且仅当当前节点及其所有后代与子树完全相同时,返回true

迭代法

  • 遍历策略:层序遍历(BFS),按层检查每个节点。
  • 匹配条件:使用双队列同步比较,确保每个对应节点的结构和值一致。

对比分析

方法遍历方式时间复杂度空间复杂度适用场景
递归法深度优先(DFS)O(m*n)O(max(h1,h2))树较浅,递归栈空间充足
迭代法广度优先(BFS)O(m*n)O(max(w1,w2))避免递归栈溢出

其中,m和n分别为主树和子树的节点数,h为树的高度,w为树的最大宽度。

五、常见误区与边界条件

1. 空树处理

  • 子树为空:题目规定空树是任何树的子树,因此直接返回true
  • 主树为空:若主树为空,仅当子树也为空时返回true,否则返回false

2. 结构与值的双重匹配

  • 示例:主树[1,1],子树[1]
    虽然主树存在节点值为1的子树,但结构不同(主树有两个节点),因此返回false

3. 部分路径匹配问题

  • 示例:主树[3,4,5,1,2,null,null,null,null,0],子树[4,1,2]
    主树的左子树路径为4→1→2,但2的右子节点存在0,与子树结构不符,故返回false

六、总结

核心算法思路

  1. 遍历主树:递归或迭代方式遍历每个节点。
  2. 检查子树:对每个节点,递归或迭代比较其与目标子树的结构和值。

代码优化建议

  1. 递归法:简洁直观,但可能导致栈溢出,适用于树高较小的场景。
  2. 迭代法:避免栈溢出,但代码复杂度较高,需维护双队列同步遍历。

关键技巧

  • 双队列同步遍历:确保主树和子树的对应节点被正确比较。
  • 层序遍历:通过队列按层处理节点,适合大规模数据。

理解这两种解法的核心逻辑后,可灵活应对类似的树结构匹配问题,如判断树的子结构、树的镜像等变体。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/80183.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Springboot 异步场景 使用注解 @Async 及 自定义线程池分模块使用

目录 前言一、Springboot项目如何开启异步&#xff1f;二、存在的问题三、自定义线程池四、自定义线程池使用五、阻塞队列和拒绝策略 前言 当开发中遇到不影响主流程任务时&#xff0c;使用异步去处理。 如有以下场景&#xff1a; 1、业务需要生成一个季度的数据进行员工排名&…

【GNN笔记】Signed Graph Convolutional Network(12)【未完】

视频链接&#xff1a;《图神经网络》 Signed Graph Convolutional Network 之前介绍的GNN模型主要集中在无符号的网络&#xff08;或仅由正链接组成的图&#xff09;上&#xff0c;符号 图带来的挑战&#xff0c;主要集中在于 否定链接&#xff0c;与正链接相比&#xff0c;它不…

米勒电容补偿的理解

米勒电容补偿是使运放放大器稳定的重要手法&#xff0c;可以使两级运放的两个极点分离&#xff0c;从而可以得到更好的相位裕度。 Miller 电容补偿的本质是增加一条通路流电流&#xff0c;流电流才是miller效应的本质。给定一个相同的输入&#xff0c;Miller 电容吃掉的电流比…

CVE-2017-8046 漏洞深度分析

漏洞概述 CVE-2017-8046 是 Spring Data REST 框架中的一个高危远程代码执行漏洞&#xff0c;影响版本包括 Spring Data REST < 2.5.12、2.6.7、3.0 RC3 及关联的 Spring Boot 和 Spring Data 旧版本。攻击者通过构造包含恶意 SpEL&#xff08;Spring Expression Language&…

qt文本边框设置

// 计算文本的大致尺寸 QFontMetrics fm(textEditor->font()); QRect textRect fm.boundingRect(textItem->toPlainText()); // 设置编辑框大小&#xff0c;增加一些边距 const int margin 10; textEditor->setGeometry( center.x() - textRect.width()/2 - margin,…

Java 与 面向对象编程(OOP)

Java 是典型的纯面向对象编程语言&#xff08;Pure Object-Oriented Language&#xff09;&#xff0c;其设计严格遵循面向对象&#xff08;OOP&#xff09;的核心原则。以下是具体分析&#xff1a; 1. Java 的面向对象核心特性 (1) 一切皆对象 Java 中几乎所有的操作都围绕…

导出导入Excel文件(详解-基于EasyExcel)

前言&#xff1a; 近期由于工作的需要&#xff0c;根据需求需要导出导入Excel模板。于是自学了一下下&#xff0c;在此记录并分享&#xff01;&#xff01; EasyExcel&#xff1a; 首先我要在这里非常感谢阿里的大佬们&#xff01;封装这么好用的Excel相关的API&#xff0c;真…

python版本管理工具-pyenv轻松切换多个Python版本

在使用python环境开发时&#xff0c;相信肯定被使用版本所烦恼&#xff0c;在用第三方库时依赖兼容的python版本不一样&#xff0c;有没有一个能同时安装多个python并能自由切换的工具呢&#xff0c;那就是pyenv&#xff0c;让你可以轻松切换多个Python 版本。 pyenv是什么 p…

Elasticsearch 索引副本数

作者&#xff1a;来自 Elastic Kofi Bartlett 解释如何配置 number_of_replicas、它的影响以及最佳实践。 更多阅读&#xff1a;Elasticsearch 中的一些重要概念: cluster, node, index, document, shards 及 replica 想获得 Elastic 认证&#xff1f;查看下一期 Elasticsearc…

AXI4总线协议 ------ AXI_LITE协议

一、AXI 相关知识介绍 https://download.csdn.net/download/mvpkuku/90841873 AXI_LITE 选出部分重点&#xff0c;详细文档见上面链接。 1.AXI4 协议类型 2.握手机制 二、AXI_LITE 协议的实现 1. AXI_LITE 通道及各通道端口功能介绍 2.实现思路及框架 2.1 总体框架 2.2 …

idea运行

各种小kips Linuxidea上传 Linux 部署流程 1、先在idea打好jar包&#xff0c;clean之后install 2、在Linux目录下&#xff0c;找到对应项目目录&#xff0c;把原来的jar包放在bak文件夹里面 3、杀死上一次jar包的pid ps -ef|grep cliaidata.jar kill pid 4、再进行上传新的jar…

FPGA: XILINX Kintex 7系列器件的架构

本文将详细介绍Kintex-7系列FPGA器件的架构。以下内容将涵盖Kintex-7的核心架构特性、主要组成部分以及关键技术&#xff0c;尽量全面且结构化&#xff0c;同时用简洁的语言确保清晰易懂。 Kintex-7系列FPGA架构概述 Kintex-7是Xilinx 7系列FPGA中的中高端产品线&#xff0c;基…

【LLM】大模型落地应用的技术 ——— 推理训练 MOE,AI搜索 RAG,AI Agent MCP

【LLM】大模型落地应用的技术 ——— 推理训练MOE&#xff0c;AI搜索RAG&#xff0c;AI Agent MCP 文章目录 1、推理训练 MOE2、AI搜索 RAG3、AI Agent MCP 1、推理训练 MOE MoE 是模型架构革新&#xff0c;解决了算力瓶颈。原理是多个专家模型联合计算。 推理训练MoE&#xff…

10 web 自动化之 yaml 数据/日志/截图

文章目录 一、yaml 数据获取二、日志获取三、截图 一、yaml 数据获取 需要安装 PyYAML 库 import yaml import os from TestPOM.common import dir_config as Dir import jsonpathclass Data:def __init__(self,keyNone,file_name"test_datas.yaml"):file_path os…

中exec()函数因$imagePath参数导致的命令注入漏洞

exec(zbarimg -q . $imagePath, $barcodeList, $returnVar); 针对PHP中exec()函数因$imagePath参数导致的命令注入漏洞&#xff0c;以下是安全解决方案和最佳实践&#xff1a; 一、漏洞原理分析 直接拼接用户输入$imagePath到系统命令中&#xff0c;攻击者可通过注入特殊字…

this.$set的用法-响应式数据更新

目录 一、核心作用 三、使用场景与示例 1. 给对象添加新属性 四、与 Vue.set 的关系 五、底层原理 六、Vue 3 的替代方案 七、最佳实践 八、常见问题 Q&#xff1a;为什么修改嵌套对象属性不需要 $set&#xff1f; Q&#xff1a;$set 和 $forceUpdate 的区别&#xf…

【生成式AI文本生成实战】DeepSeek系列应用深度解析

目录 &#x1f31f; 前言&#x1f3d7;️ 技术背景与价值&#x1fa79; 当前技术痛点&#x1f6e0;️ 解决方案概述&#x1f465; 目标读者说明 &#x1f9e0; 一、技术原理剖析&#x1f4ca; 核心概念图解&#x1f4a1; 核心作用讲解&#x1f527; 关键技术模块说明⚖️ 技术选…

c/c++的opencv的图像预处理讲解

OpenCV 图像预处理核心技术详解 (C/C) 图像预处理是计算机视觉任务中至关重要的一步。原始图像往往受到噪声、光照不均、尺寸不一等多种因素的影响&#xff0c;直接用于后续分析&#xff08;如特征提取、目标检测、机器学习模型训练等&#xff09;可能会导致性能下降或结果不准…

使用 Docker 部署 React + Nginx 应用教程

目录 1. 创建react项目结构2. 创建 .dockerignore3. 创建 Dockerfile4. 创建 nginx.conf5. 构建和运行6. 常用命令 1. 创建react项目结构 2. 创建 .dockerignore # 依赖目录 node_modules npm-debug.log# 构建输出 dist build# 开发环境文件 .git .gitignore .env .env.local …

Java 流(Stream)API

一、理论说明 1. 流的定义 Java 流&#xff08;Stream&#xff09;是 Java 8 引入的新特性&#xff0c;用于对集合&#xff08;如 List、Set&#xff09;或数组进行高效的聚合操作&#xff08;如过滤、映射、排序&#xff09;和并行处理。流不存储数据&#xff0c;而是按需计…