代码随想录第十四天|二叉树part02--226.翻转二叉树、101.对称二叉树、104.二叉树的最大深度、111.二叉树的最小深度

资料引用:

226.翻转二叉树(226.翻转二叉树)

101.对称二叉树(101.对称二叉树)

104.二叉树的最大深度(104.二叉树的最大深度)

111.二叉树的最小深度(111.二叉树的最小深度)

226.翻转二叉树(226.翻转二叉树)

题目分析:

给定一棵二叉树的根节点root,翻转二叉树,使每一棵子树的根节点的左右孩子交换,最后返回根节点。

解题重点:

选择合适的遍历方式以便于处理。

解题思路:

考虑采取递归的遍历方式进行处理,使用前序或后序遍历皆可。

  • 递归函数的参数:待处理的子树根节点
  • 递归函数的返回值:处理完毕的子树根节点
  • 递归函数的终止条件:遇到空节点直接返回
  • 递归函数的单层递归逻辑:
    • 前序遍历:终止条件判断、swap左右孩子,递归进入左孩子,递归进入右孩子,返回当前根节点
    • 后序遍历:终止条件判断、递归进入左孩子,递归进入右孩子,swap左右孩子,返回当前根节点
注意:

为什么不使用中序遍历?

因为中序遍历是左中右,先完成对左子树的翻转,再将左右子树互换,此时若再对当前的右子树做翻转,实际上是对互换前的、已经完成翻转的“前左子树”做翻转。

修改方式:左中“左”

总结反思:

需要把握好不同遍历方式下处理操作的顺序,尤其是前(后)序和中序之间的区别。

class Solution {public TreeNode invertTree(TreeNode root) {if (root == null) return root;swap_Kids(root);invertTree(root.left);invertTree(root.right);return root;}public void swap_Kids (TreeNode root) {TreeNode tmpNode = root.left;root.left = root.right;root.right = tmpNode;return;}
}

101.对称二叉树(101.对称二叉树)

题目分析:

给定一个二叉树的根节点root,判断其是否为轴对称的,即翻转后树的节点值是否不变(包括空值)。

解题重点:

选择合适的遍历方式,方便比较。

简单思路:

先遍历取节点值,包括空值,用StringBuilder存储(便于存储空值),

再翻转二叉树,

最后用相同的方式遍历取节点值,实时比较是否与第一步得到的字符数组相同。

此处采取前序遍历。

class Solution {public boolean isSymmetric(TreeNode root) {if (root == null) return true;StringBuilder sb1 = new StringBuilder();StringBuilder sb2 = new StringBuilder();preOrder(root, sb1);invertTree(root);preOrder(root, sb2);return sb1.toString().equals(sb2.toString());}public void preOrder(TreeNode root, StringBuilder sb){if(root == null) {sb.append("\0");return;}sb.append(Integer.toString(root.val));preOrder(root.left, sb);preOrder(root.right, sb);}public TreeNode invertTree(TreeNode root) {if (root == null) return root;swap_Kids(root);invertTree(root.left);invertTree(root.right);return root;}public void swap_Kids (TreeNode root) {TreeNode tmpNode = root.left;root.left = root.right;root.right = tmpNode;return;}
}

推荐思路:

比较的不是二叉树的左右节点,比较的是根节点的左子树和右子树是不是相互翻转的,即比较对象是左右子树。

因此,在递归遍历过程中,要同时遍历两棵树。

由翻转的特性,我们定义:靠近中轴的是里侧节点,远离中轴的外侧节点。

选择“后序遍历”:通过递归函数的返回值判断两个子树之间的内侧节点和外侧节点是否相等。

准确来说:对两个子树的遍历应当分别为左右中和右左中。

定义递归比较函数compare如下:

    1. 递归函数的参数:左右子树节点
    2. 递归函数的返回值:布尔值
    3. 确定终止条件:
      1. 节点为空的情况:
        1. 左空,右非空,return false
        2. 左非空,右空,return false
        3. 左右都为空,对称,return true
      1. 节点非空的情况:
        1. 左右都非空,节点值不同false,相同继续
    1. 递归函数的单层递归逻辑:处理 左右节点都不为空,且数值相同的情况
      1. 递归比较左孩子的左孩子 和 右孩子的右孩子(外侧节点)
      2. 递归比较左孩子的右孩子 和 右孩子的左孩子(里侧节点)
      3. 取前两者的逻辑并,返回该值。
class Solution {public boolean isSymmetric(TreeNode root) {if (root == null) return true;return compareLR(root.left, root.right);}public boolean compareLR(TreeNode left, TreeNode right) {// 首先排除节点为空的情况if (left == null && right != null) return false;else if (left != null && right == null) return false;else if (left == null && right == null) return true;// 然后排除节点不为空时,两节点值不相等的情况else if (left.val != right.val) return false;// 递归比较外侧节点和里侧节点,取逻辑并boolean outside = compareLR(left.left, right.right);boolean inside = compareLR(left.right, right.left);boolean isSame = outside && inside;return isSame;}
}

总结反思:

学会根据任务需求灵活调整遍历方式进行比较。

递归中的三要素需要在掌握的基础上根据实际情况来调整完善,尤其是终止条件的合理设定,非常重要。

104.二叉树的最大深度(104.二叉树的最大深度)

题目分析:

给定一个二叉树,返回其最大深度。

解题重点:

对于一个二叉树,求其最大深度,则在递归遍历过程中增加deep参数的传递。

注意:

最大深度定义为:从根节点到最远叶子节点的最长路径上的节点数,因此最小深度从1开始(根节点不为空,若为空返回0)。

解题思路:

构造递归函数getMaxDepth如下:

  1. 递归函数的参数:节点node,当前深度deep
  2. 递归函数的返回值:最终深度deep,整型
  3. 递归函数的终止条件:遇到空节点,返回当前deep
  4. 递归函数的单层递归逻辑:节点为空,返回deep。节点不为空,deep++,递归查询左子树的最大深度left_depth和右子树的最大深度right_depth,取较大者返回。

总结:

注意通过递归函数的参数传递,实现当前深度deep的记录,并注意比较左右子树取较大者。

class Solution {public int maxDepth(TreeNode root) {return getMaxDepth(root, 0);}public int getMaxDepth(TreeNode root, int deep) {if (root == null) return deep;deep++;int left_depth = getMaxDepth(root.left, deep);int right_depth = getMaxDepth(root.right, deep);return left_depth > right_depth ? left_depth : right_depth;}
}

111.二叉树的最小深度(111.二叉树的最小深度)

题目分析:

给定一个二叉树的根节点root,找出其最小深度。

注意:

最小深度的定义:从根节点到最近叶子结点的最短路径上的节点数。

解题重点:

需要排除左(右)子树为空的这条路径

解题思路与优化:

后序遍历:

  • 自底向上求高度(等价于求深度),
  • 终止条件是遇到空节点时返回0(叶子节点为从1开始)
  • 通过递归的逐级返回进行自增即可
  • 注意排除节点为空的情况,不可作为最小深度比较对象

前序遍历:

  • 自顶向下求深度
  • 终止条件是遇到空节点时不自增,直接返回当前积累深度deep
  • 通过递归返回的是最底层的计算结果,是通过逐级向下递归时自增的
  • 需要额外增加参数--当前深度deep,因此需要构造新的递归函数
  • 相较后序并不简洁,但也可实现。

层序遍历(迭代法):

  • 层序遍历通过队列实现
  • 需要注意的是:只有当左右孩子都为空,才说明是抵达叶子节点,否则继续
  • 首次抵达叶子结点时,由于层序遍历是从上往下遍历,所以正是最近叶子节点

总结反思:

理解前序遍历和后序遍历的“方向”区别,根据实际情景选取适合的遍历方式。

理解题意很重要,不要经验主义下判断~

/*后序遍历 递归法*/
class Solution {/*该解法实际是后序遍历,相当于求最小高度,等价于求最小深度 */public int minDepth(TreeNode root) {if (root == null) return 0;int leftDepth = minDepth(root.left);int rightDepth = minDepth(root.right);if (root.left == null) return rightDepth+1;if (root.right == null) return leftDepth+1;return leftDepth < rightDepth ? leftDepth+1 : rightDepth+1;}
}
/*前序遍历 递归法*/
class Solution {public int minDepth(TreeNode root) {return getMinDepth(root, 0);}public int getMinDepth(TreeNode root, int deep) {if (root == null) return deep;deep++;int left_depth = 0;int right_depth = 0;if (root.left == null) return getMinDepth(root.right, deep);else if (root.right == null) return getMinDepth(root.left, deep);left_depth = getMinDepth(root.left, deep);right_depth = getMinDepth(root.right, deep);return left_depth < right_depth ? left_depth : right_depth;}
}
/*层序遍历 迭代法*/
class Solution {public int minDepth(TreeNode root) {if (root == null) {return 0;}Deque<TreeNode> deque = new ArrayDeque<>();deque.offer(root);int depth = 0;while (!deque.isEmpty()) {int size = deque.size();depth++;for (int i = 0; i < size; i++) {TreeNode poll = deque.poll();if (poll.left == null && poll.right == null) {// 因为从上往下遍历,所以是最近叶子结点,该值就是最小值,直接返回depthreturn depth;}if (poll.left != null) {deque.offer(poll.left);}if (poll.right != null) {deque.offer(poll.right);}}}return depth;}
}

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

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

相关文章

二阶线性微分方程的幂级数解法

内容来源 常微分方程(第四版) (王高雄,周之铭,朱思铭,王寿松) 高等教育出版社 考虑二阶齐次线性微分方程 d 2 y d x 2 p ( x ) d y d x q ( x ) y 0 \frac{\mathrm{d}^2y}{\mathrm{d}x^2} p(x)\frac{\mathrm{d}y}{\mathrm{d}x}q(x)y0 dx2d2y​p(x)dxdy​q(x)y0 满足初值条…

Java基础面向对象(String类)

String 特点 是内存中常量, 值在内存中一旦创建, 不可改 更改String类型引用的值本质上是将引用指向了一个新的字符串地址 String s1 "abc";String s2 s1;//引用s1的地址赋值给了s2 ​s2 "edf";//让s2指向新字符串 ​System.out.println("s1: &q…

【系统架构设计师】真题论文: 论软件质量保证及其应用(包括解题思路和素材)

更多内容请见: 备考系统架构设计师-专栏介绍和目录 文章目录 真题题目(2017年 试题4)解题思路论文素材参考软件质量保证定义和重要性软件质量保证在软件开发生命周期中的应用真题题目(2017年 试题4) 软件质量保证 (Software Quality Assurance. SQA) 是指为保证软件系统或…

LeetCode763. 划分字母区间(2024冬季每日一题 23)

给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段&#xff0c;同一字母最多出现在一个片段中。 注意&#xff0c;划分结果需要满足&#xff1a;将所有划分结果按顺序连接&#xff0c;得到的字符串仍然是 s 。 返回一个表示每个字符串片段的长度的列表。 示例 1&a…

【C++】深入优化计算题目分析与实现

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;第一题&#xff1a;圆的计算我的代码实现代码分析改进建议改进代码 老师的代码实现代码分析可以改进的地方改进代码 &#x1f4af;第二题&#xff1a;对齐输出我的代码实现…

6.824/6.5840 Lab 3: Raft——Part 3B3C

芙蓉花又栖满了枝头 奈何蝶难留 漂泊如江水向东流 望断门前隔岸的杨柳 寂寞仍不休 我无言让眼泪长流 ——山外小楼夜听雨 完整代码见&#xff1a; https://github.com/SnowLegend-star/6.824 在完成Lab之前&#xff0c;务必把论文多读几遍&#xff0c;力求完全理解Leader选举、…

LeetCode - #150 逆波兰表达式求值

文章目录 前言1. 描述2. 示例3. 答案关于我们 前言 我们社区陆续会将顾毅&#xff08;Netflix 增长黑客&#xff0c;《iOS 面试之道》作者&#xff0c;ACE 职业健身教练。&#xff09;的 Swift 算法题题解整理为文字版以方便大家学习与阅读。 LeetCode 算法到目前我们已经更新…

使用go实现一个简单的rpc

什么是rpc, rpc是干什么的?几种协议的压测数据对比:tcphttp 使用tcp实现一个简单的rpc服务 什么是rpc, rpc是干什么的? rpc的作用就是实现远程的服务调用 工作流程: 客户端携带服务信息(服务名,方法名)数据 去请求服务端,服务端拿到数据,解析后执行对应的方法,将结果返回给客…

【C++】continue语句、goto语句

1、continue 语句 作用&#xff1a;在循环语句中&#xff0c;跳过本次循环中余下尚未执行的语句。继续下一次循环。 注意&#xff1a;continue只能用于循环中。 示例&#xff1a; 代码&#xff1a; //continue的用法 #include<iostream> using namespace std; int ma…

最长最短单词

最长最短单词 C语言实现C实现Java实现Python实现 &#x1f490;The Begin&#x1f490;点点关注&#xff0c;收藏不迷路&#x1f490; 输入1行句子&#xff08;不多于200个单词&#xff0c;每个单词长度不超过100&#xff09;&#xff0c;只包含字母、空格和逗号。单词由至少一…

ESP32项目 --- 智能门锁(WiFi 蓝牙 OTA)

1 项目简介 1.1 项目概述 本项目是实现一款智能门锁中的智能控制部分, 可以应用在家庭, 办公室等任何使用门锁的场所. 本项目实现了以下主要功能: &#xff08;1&#xff09;通过按键配置密码 &#xff08;2&#xff09;通过按键输入密码开锁 &#xff08;3&#xff09;录…

【Qt】QTableView选中行发生变化时触发的信号

问题 QTableView选中的行发生变化时&#xff0c;使用的信号是QTableView的selectionModel()里的currentChanged信号&#xff0c;界面点击行来回切换&#xff0c;发现怎么也触发不了&#xff1f; 原因 信号槽连接放在了QTableView数据初始化前面&#xff0c;这时候QTableView…

洛谷题单-入门2-分支结构-python-下

找出出现的最早的最大值 count 0 list_number [] while True:list_number.append(list(map(int, input().split())))count 1if count 7:breaklist2_number_total []for i1,i2 in list_number:list2_number_total.append(i1i2)target max(list2_number_total)index 0 if…

Java Collections 深度探索

在 Java 编程中&#xff0c;java.util.Collections是一个非常重要的工具类&#xff0c;它提供了一系列对集合进行操作的静态方法。本文将深入探讨 Java Collections 的功能、用法、优势以及在实际编程中的应用。 一、引言 Java Collections 框架为开发者提供了一套强大而灵活…

Taro小程序开发随记

处理taro小程序显示wangeditor内的a标签跳转 Taro.options.html.transformElement (el) > {if (el.props.class h5-a) {el.__handlers.tap [() > toWebView(el.props.href)]}return el } 处理wangeditor富文本内容中图片视频到小程序中展示问题 <view class&qu…

Pytorch使用手册-What is torch.nn really?(专题九)

我们建议将本教程作为 notebook 而不是脚本运行。要下载 notebook(.ipynb)文件,请点击页面顶部的链接。 PyTorch 提供了精心设计的模块和类,如 torch.nn、torch.optim、Dataset 和 DataLoader,帮助你创建和训练神经网络。为了充分利用这些工具的强大功能并根据你的问题进…

框架模块说明 #05 权限管理_03

背景 权限设计可以分为两个主要方面&#xff1a;操作权限和数据权限。前两篇文章已经详细介绍了操作权限的设计与实现&#xff0c;以及如何将其与菜单关联起来的具体方法。本篇将聚焦于数据权限&#xff0c;为您深入讲解相关的设计与实现方式。 全局开关 Value("${syst…

Linux网络编程之---多线程实现并发服务器

下面我们来使用tcp集合多线程实现并发服务器 一.服务端 #include <stdio.h> #include <arpa/inet.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <pthread.h>typedef struct sockinfo {char ip[16];unsigne…

二分查找!

问题描述 小明在图书馆借阅书籍&#xff0c;图书馆的书籍在系统中按序号顺次排列&#xff0c;小明在借阅后&#xff0c;需在系统中从“在馆书籍列表”中将该书删除。请帮助小明编写一个函数&#xff0c;在现有列表{1, 3, 5, 6, 7, 10, 12, 14, 26, 32, 35, 39, 42, 45, 54, 56…

按vue组件实例类型实现非侵入式国际化多语言翻译

#vue3##国际化##本地化##international# web界面国际化&#xff0c;I18N&#xff08;Internationalization&#xff0c;国际化&#xff09;&#xff0c;I11L(International&#xff0c;英特纳雄耐尔)&#xff0c;L10N&#xff08;Localization&#xff0c;本地化&#xff09;&…