算法题 翻转等价二叉树

951. 翻转等价二叉树

问题描述

我们可以对二叉树的任意节点进行翻转操作:交换该节点的左右子树。

如果可以通过一系列翻转操作使得二叉树root1变成root2,则称这两棵树是翻转等价的。

给定两棵二叉树的根节点root1root2,如果它们是翻转等价的,返回true;否则返回false

示例

输入: root1 = [1,2,3,4,5,6,null,null,null,7,8], root2 = [1,3,2,null,6,4,5,null,null,null,null,8,7] 输出: true 解释: 我们可以翻转root1中值为1、3和5的节点,使两棵树相等。 输入: root1 = [], root2 = [] 输出: true 输入: root1 = [], root2 = [1] 输出: false

算法思路

递归比较

核心思想

  • 两棵树翻转等价的条件:
    1. 两棵树都为空 → 等价
    2. 一棵为空,另一棵不为空 → 不等价
    3. 两棵树根节点值不同 → 不等价
    4. 两棵树根节点值相同,且满足以下任一条件:
      • 左子树与左子树等价右子树与右子树等价(不翻转)
      • 左子树与右子树等价右子树与左子树等价(翻转)

代码实现

方法一:递归比较

/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode() {} * TreeNode(int val) { this.val = val; } * TreeNode(int val, TreeNode left, TreeNode right) { * this.val = val; * this.left = left; * this.right = right; * } * } */classSolution{/** * 判断两棵二叉树是否翻转等价 * * @param root1 第一棵二叉树的根节点 * @param root2 第二棵二叉树的根节点 * @return 如果两棵树翻转等价返回true,否则返回false */publicbooleanflipEquiv(TreeNoderoot1,TreeNoderoot2){// 基础情况:两棵树都为空if(root1==null&&root2==null){returntrue;}// 一棵为空,另一棵不为空if(root1==null||root2==null){returnfalse;}// 根节点值不同if(root1.val!=root2.val){returnfalse;}// 递归检查两种情况:// 1. 不翻转:左子树对左子树,右子树对右子树// 2. 翻转:左子树对右子树,右子树对左子树return(flipEquiv(root1.left,root2.left)&&flipEquiv(root1.right,root2.right))||(flipEquiv(root1.left,root2.right)&&flipEquiv(root1.right,root2.left));}}

方法二:提前剪枝

classSolution{/** * 添加更多边界条件检查 */publicbooleanflipEquiv(TreeNoderoot1,TreeNoderoot2){// 都为空if(root1==null&&root2==null){returntrue;}// 一个为空if(root1==null||root2==null){returnfalse;}// 值不同if(root1.val!=root2.val){returnfalse;}// 都是叶子节点if(root1.left==null&&root1.right==null&&root2.left==null&&root2.right==null){returntrue;}// 递归检查return(flipEquiv(root1.left,root2.left)&&flipEquiv(root1.right,root2.right))||(flipEquiv(root1.left,root2.right)&&flipEquiv(root1.right,root2.left));}}

方法三:迭代

importjava.util.Stack;classSolution{/** * 使用栈模拟递归 */publicbooleanflipEquiv(TreeNoderoot1,TreeNoderoot2){Stack<TreeNode[]>stack=newStack<>();stack.push(newTreeNode[]{root1,root2});while(!stack.isEmpty()){TreeNode[]pair=stack.pop();TreeNodenode1=pair[0];TreeNodenode2=pair[1];// 都为空if(node1==null&&node2==null){continue;}// 一个为空或值不同if(node1==null||node2==null||node1.val!=node2.val){returnfalse;}// 检查子树匹配情况booleannormalMatch=(node1.left==null?node2.left==null:(node2.left!=null&&node1.left.val==node2.left.val));if(normalMatch){// 正常匹配:左对左,右对右stack.push(newTreeNode[]{node1.left,node2.left});stack.push(newTreeNode[]{node1.right,node2.right});}else{// 翻转匹配:左对右,右对左stack.push(newTreeNode[]{node1.left,node2.right});stack.push(newTreeNode[]{node1.right,node2.left});}}returntrue;}}

算法分析

  • 时间复杂度:O(min(N1, N2))
    • N1 和 N2 分别是两棵树的节点数
    • 最坏情况下需要遍历所有节点
  • 空间复杂度
    • 递归:O(min(H1, H2)),H1和H2是树的高度(递归栈深度)
    • 迭代:O(min(H1, H2)),栈空间

算法过程

输入:root1 = [1,2,3,4,5,6,null,null,null,7,8],root2 = [1,3,2,null,6,4,5,null,null,null,null,8,7]

  1. 根节点(1,1):值相同,检查子树
  2. 检查子树组合
    • 正常匹配:root1.left=2vsroot2.left=3→ 值不同
    • 翻转匹配:root1.left=2vsroot2.right=2root1.right=3vsroot2.left=3
  3. 递归处理(2,2)
    • 正常匹配:4 vs 45 vs 5
    • 继续递归到叶子节点
  4. 递归处理(3,3)
    • 正常匹配:6 vs 6null vs null
  5. 最终结果:所有节点都匹配,返回true

测试用例

publicstaticvoidmain(String[]args){Solutionsolution=newSolution();// 创建树节点TreeNodecreateNode(intval){returnnewTreeNode(val);}// 测试用例1:标准示例TreeNoderoot1_1=newTreeNode(1);root1_1.left=newTreeNode(2);root1_1.right=newTreeNode(3);root1_1.left.left=newTreeNode(4);root1_1.left.right=newTreeNode(5);root1_1.right.left=newTreeNode(6);root1_1.left.right.left=newTreeNode(7);root1_1.left.right.right=newTreeNode(8);TreeNoderoot2_1=newTreeNode(1);root2_1.left=newTreeNode(3);root2_1.right=newTreeNode(2);root2_1.left.right=newTreeNode(6);root2_1.right.left=newTreeNode(4);root2_1.right.right=newTreeNode(5);root2_1.right.right.right=newTreeNode(7);root2_1.right.right.left=newTreeNode(8);System.out.println("Test 1: "+solution.flipEquiv(root1_1,root2_1));// true// 测试用例2:空树System.out.println("Test 2: "+solution.flipEquiv(null,null));// true// 测试用例3:一个空一个非空TreeNodesingle=newTreeNode(1);System.out.println("Test 3: "+solution.flipEquiv(null,single));// falseSystem.out.println("Test 3b: "+solution.flipEquiv(single,null));// false// 测试用例4:单节点相同TreeNodenode1=newTreeNode(5);TreeNodenode2=newTreeNode(5);System.out.println("Test 4: "+solution.flipEquiv(node1,node2));// true// 测试用例5:单节点不同TreeNodenode3=newTreeNode(5);TreeNodenode4=newTreeNode(6);System.out.println("Test 5: "+solution.flipEquiv(node3,node4));// false// 测试用例6:完全相同的树TreeNodesame1=newTreeNode(1);same1.left=newTreeNode(2);same1.right=newTreeNode(3);TreeNodesame2=newTreeNode(1);same2.left=newTreeNode(2);same2.right=newTreeNode(3);System.out.println("Test 6: "+solution.flipEquiv(same1,same2));// true// 测试用例7:需要翻转的简单情况TreeNodeflip1=newTreeNode(1);flip1.left=newTreeNode(2);flip1.right=newTreeNode(3);TreeNodeflip2=newTreeNode(1);flip2.left=newTreeNode(3);flip2.right=newTreeNode(2);System.out.println("Test 7: "+solution.flipEquiv(flip1,flip2));// true// 测试用例8:复杂的不等价情况TreeNodediff1=newTreeNode(1);diff1.left=newTreeNode(2);diff1.right=newTreeNode(3);TreeNodediff2=newTreeNode(1);diff2.left=newTreeNode(2);diff2.right=newTreeNode(4);// 值不同System.out.println("Test 8: "+solution.flipEquiv(diff1,diff2));// false// 测试用例9:结构不同TreeNodestruct1=newTreeNode(1);struct1.left=newTreeNode(2);TreeNodestruct2=newTreeNode(1);struct2.right=newTreeNode(2);System.out.println("Test 9: "+solution.flipEquiv(struct1,struct2));// true (可以通过翻转)}

关键点

  1. 递归

    • 每个节点都有两种匹配方式:正常或翻转
    • 只要有一种方式能让整棵树匹配就返回true
  2. 边界条件处理

    • 空树
    • 节点值不同
    • 结构不同
  3. 翻转

    • 翻转操作可以应用在任意节点上
    • 不需要实际执行翻转,只需要验证是否存在翻转序列

常见问题

  1. 为什么不需要考虑多次翻转同一个节点?
    • 翻转两次等于没有翻转,所以每个节点最多翻转一次

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

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

相关文章

如何在n8n中构建多智能体系统?一份即学即会的四步搭建指南攻略

n8n 是一个基于节点的AI工作流自动化构建器&#xff0c;允许你从简单开始&#xff0c;仅在需要时增加复杂性。我们可以轻松地在n8n中演示如何将多个服务、触发器和顺序步骤连接到一个自动化流程中。我们将构建一个分层多智能体系统&#xff0c;其中一个主智能体协调两个专门的子…

2026文旅AI营销榜单:原圈科技领衔破解增长焦虑

面对文旅行业获客难、体验同质化的困境,AI营销成为破局关键。本文揭晓的2026年AI营销服务商实力榜单中,原圈科技凭借其全链路智能体解决方案和深厚的行业积累,在多个维度下表现突出,被普遍视为企业实现智慧增长、优化ROI的理想合作伙伴。该榜单将助您精准把握AI时代脉搏。引言:…

如何操作双极板材料四探针低阻测试仪?

如何操作双极板材料四探针低阻测试仪&#xff1f;操作双极板材料四探针低阻测试仪的关键在于规范流程和细节把控&#xff0c;我来帮你梳理核心步骤&#xff1a;一、操作前准备 样品处理‌确保双极板材料表面平整、无氧化层或污染物&#xff0c;必要时用酒精或超声波清洗。 测量…

中国人民大学打造AI创意写作新帮手:让机器既聪明又有想象力

创意写作一直是人类独有的艺术天赋&#xff0c;但随着人工智能的快速发展&#xff0c;机器是否也能拥有创造力成为了一个引人深思的话题。最近&#xff0c;中国人民大学联合快手科技的研究团队发表了一项突破性研究&#xff0c;他们开发出了一个名为DPWriter的AI写作系统&#…

双极板材料四探针低阻/接触电阻测试仪

双极板材料四探针低阻/接触电阻测试仪双极板材料四探针低阻/接触电阻测试仪产品概述&#xff1a;全面满足双极板测试需求 一、核心功能与特点 我们的双极板材料四探针低阻/接触电阻测试仪是一款集成了多项先进技术的专业测量设备。其主要功能包括&#xff1a;双模式测量‌&…

企业内部在线学习培训系统

企业内部在线学习培训系统是一套功能齐全的在线学习管理系统&#xff0c;其拥有强大的功能&#xff0c;覆盖从课程制作、学习管理、考核评估到数据分析的全流程&#xff0c;它还作为一个私有化平台&#xff0c;可以在云服务器或者局域网本地服务器上私有化部署。以下是企业内训…

将 Java 代码嵌入 iOS 系统需要特殊的技术方案

将 Java 代码嵌入 iOS 系统需要特殊的技术方案&#xff0c;因为 iOS 原生不支持 Java 运行时环境。以下是几种实现方式及示例&#xff1a;## 1. **J2ObjC&#xff08;Google 官方工具&#xff09;**将 Java 代码转换为 Objective-C&#xff0c;然后集成到 iOS 项目中。### 示例…

拒稿退散!宏智树 AI 手把手教你写出期刊录用级论文

作为深耕论文写作科普的教育博主&#xff0c;后台每天都被科研人的投稿焦虑刷屏&#xff1a;“选题太老被拒稿”“文献堆砌逻辑乱”“查重率高改到崩溃”“AI 痕迹明显被打回”…… 一篇期刊论文从构思到见刊&#xff0c;往往要经历数次甚至数十次修改。别慌&#xff01;今天就…

天天写业务代码,如何破局?

无法与业务耦合的开发工程师&#xff0c;职业发展往往更易触碰到天花板。只有在经历过快速迭代的业务需求锤炼、海量用户规模场景的“拷打”以后&#xff0c;工程师才能向架构师甚至更高的技术岗位进阶。腾讯技术专家&#xff0c;万字长文带你剖析业务开发的本质&#xff01;长…

游戏外包开发的上线

对于游戏外包开发&#xff0c;“上线”不仅是一个简单的发布动作&#xff0c;它是从开发交付到市场运营的关键转折点。在2026年的市场与技术环境下&#xff0c;游戏外包上线通常涉及以下五个关键阶段&#xff1a;1. 验收与质量交付在正式上线前&#xff0c;你需要确保外包团队交…

迈向可持续、智慧与融合:中国城市轨道交通未来发展路径研究

目录 1. 引言&#xff1a;转型期的机遇与挑战 2. 核心驱动力一&#xff1a;人工智能赋能&#xff0c;迈向深度智能化 3. 核心驱动力二&#xff1a;全生命周期绿色低碳转型 4. 核心驱动力三&#xff1a;融合创新与可持续发展 5. 基石与保障&#xff1a;安全韧性与新质生产力…

网络安全详解大全,助力每一个网安梦想!

网络安全的全面解析 一、网络安全的概念与重要性 网络安全&#xff08;Cyber Security&#xff09;是指网络系统的硬件、软件及其系统中的数据受到保护&#xff0c;不因偶然的或者恶意的原因而遭受到破坏、更改、泄露&#xff0c;系统连续可靠正常地运行&#xff0c;网络服务…

告别 PPT 创作焦虑!宏智树 AI:一键拿捏开题、答辩、汇报全场景学术演示

作为深耕论文写作科普的教育博主&#xff0c;后台每天都被粉丝的 PPT 难题刷屏&#xff1a;“开题 PPT 改了 N 版&#xff0c;导师仍说逻辑混乱”“答辩 PPT 文字堆砌&#xff0c;评委抓不住核心创新点”“工作汇报 PPT 设计粗糙&#xff0c;展现不出成果价值”。 学术 PPT 的…

1480. 找字典码最小的字符串

1480. 找字典码最小的字符串 问题描述 编写程序&#xff0c;针对输入的 NNN 个不同的字符串&#xff0c;输出其中字典码最小的字符串。 输入 输入第一行给出正整数 NNN&#xff1b;随后 NNN 行&#xff0c;每行给出一个长度小于 80 的非空字符串&#xff0c;其中不会出现换…

【tensorRT从零起步高性能部署】21-TensorRT基础-实现模型的推理过程

1. inference案例&#xff1a;推理全流程详解 void inference(){// ------------------------------ 1. 准备模型并加载 ----------------------------TRTLogger logger;auto engine_data load_file("engine.trtmodel");// 执行推理前&#xff0c;需要创建一个推理…

AD25 —走线时如何添加过孔(加过孔不换层 / 加过孔换层)

走线模式下&#xff0c;可以直接加过孔&#xff1a; 不换层&#xff1a;按2换层&#xff1a;按小键盘上的&#xff1a;*

MySQL数据可视化实战:从查询到图表的全流程

数据可视化是将枯燥的数据库数据转化为直观图表的核心手段&#xff0c;而 MySQL 作为最常用的关系型数据库&#xff0c;并非只能做数据存储和查询 —— 结合合理的查询技巧与可视化工具&#xff0c;你可以用 MySQL 快速实现从 “数据提取” 到 “图表展示” 的全链路可视化分析…

新一代城市轨道交通云原生智能体协同架构:从智慧中枢到自主进化的未来

目录 1. 引言&#xff1a;架构演进是可持续发展的技术先导 2. 理论基础与架构设计 3. 关键协同机制与运行范式 4. 应用价值与行业变革意义 5. 实施挑战与演进路径 6. 结论 摘要&#xff1a;随着城市轨道交通迈入以“云数智”深度融合为特征的新阶段&#xff0c;传统的中心…

输入某水果店的水果名称,进价,售价,库存,计算库存预警值(库存低于10斤),输出需补货的水果。

为你完整设计一个水果店库存预警与补货分析系统&#xff0c;结合大数据与智能管理课程的思想&#xff0c;从场景到代码、从模块到文档&#xff0c;全部覆盖。1. 实际应用场景 & 痛点引入场景你是某水果店的老板或库存管理员&#xff0c;手头有水果数据&#xff08;水果名称…

AI赋能工作全攻略:从小白到高手的实用指南(建议收藏)

AI作为"智商情商双高的实习生"&#xff0c;可通过高容错、高频次方式融入日常工作。文章从数字化与AI关系入手&#xff0c;详述生成式AI应用方法&#xff0c;提出"1个秘密、2个心法、3个行动、4个资源、5个阶段"框架&#xff0c;指导读者从简单聊天框应用起…