【刷爆力扣之101.对称二叉树-100.相同的树】

embedded/2024/9/25 23:25:45/

101.对称二叉树

1.递归法

递归三部曲

  1. 确定递归函数的参数和返回值

因为我们要比较的是根节点的两个子树是否是相互翻转的,进而判断这个树是不是对称树,所以要比较的是两个树,参数自然也是左子树节点和右子树节点。

返回值自然是bool类型。

代码如下:

private boolean doIsSymmetric(TreeNode left, TreeNode right) {
  1. 确定终止条件

要比较两个节点数值相不相同,首先要把两个节点为空的情况弄清楚!否则后面比较数值的时候就会操作空指针了。

节点为空的情况有:(注意我们比较的其实不是左孩子和右孩子,所以如下我称之为左节点右节点

  • 左节点为空,右节点不为空,不对称,return false
  • 左不为空,右为空,不对称 return false
  • 左右都为空,对称,返回true

此时已经排除掉了节点为空的情况,那么剩下的就是左右节点不为空:

  • 左右都不为空,比较节点数值,不相同就return false

此时左右节点不为空,且数值也不相同的情况我们也处理了。

代码如下:

// 若同时为 null
if (left == null && right == null) {return true;
}
// 若有一个为 null (有上一轮筛选,另一个肯定不为 null)
if (left == null || right == null) {return false;
}
// 若两节点值不相等,返回false
if (!Objects.equals(left.val, right.val)) {return false;
}
  1. 确定单层递归的逻辑

此时才进入单层递归的逻辑,单层递归的逻辑就是处理 左右节点都不为空,且数值相同的情况。

  • 比较二叉树外侧是否对称:传入的是左节点的左孩子,右节点的右孩子。
  • 比较内侧是否对称,传入左节点的右孩子,右节点的左孩子。
  • 如果左右都对称就返回true ,有一侧不对称就返回false 。

代码如下:

boolean a = doIsSymmetric(left.left, right.right);
boolean b = doIsSymmetric(left.right, right.left);
return a && b;

如上代码中,我们可以看出使用的遍历方式,左子树左右中,右子树右左中,所以我把这个遍历顺序也称之为“后序遍历”(尽管不是严格的后序遍历)。

最后递归的Java整体代码如下:

public boolean isSymmetric(TreeNode root) {if (root == null) {return false;}return doIsSymmetric(root, root);
}private boolean doIsSymmetric(TreeNode left, TreeNode right) {// 若同时为 nullif (left == null && right == null) {return true;}// 若有一个为 null (有上一轮筛选,另一个肯定不为 null)if (left == null || right == null) {return false;}// 若两节点值不相等,返回falseif (!Objects.equals(left.val, right.val)) {return false;}boolean a = doIsSymmetric(left.left, right.right);boolean b = doIsSymmetric(left.right, right.left);return a && b;
}

2.迭代法

这道题目我们也可以使用迭代法,但要注意,这里的迭代法可不是前中后序的迭代写法,因为本题的本质是判断两个树是否是相互翻转的,其实已经不是所谓二叉树遍历的前中后序的关系了。

这里我们可以使用队列来比较两个树(根节点的左右子树)是否相互翻转,(注意这不是层序遍历

使用队列

如下的条件判断和递归的逻辑是一样的。

代码如下:

/*** 迭代法* 使用普通队列*/
public boolean isSymmetric3(TreeNode root) {Queue<TreeNode> deque = new LinkedList<>();deque.offer(root.left);deque.offer(root.right);while (!deque.isEmpty()) {TreeNode leftNode = deque.poll();TreeNode rightNode = deque.poll();if (leftNode == null && rightNode == null) {continue;}if (leftNode == null || rightNode == null || leftNode.val != rightNode.val) {return false;}// 这里顺序与使用Deque不同deque.offer(leftNode.left);deque.offer(rightNode.right);deque.offer(leftNode.right);deque.offer(rightNode.left);}return true;
}

使用栈

细心的话,其实可以发现,这个迭代法,其实是把左右两个子树要比较的元素顺序放进一个容器,然后成对成对的取出来进行比较,那么其实使用栈也是可以的。

/*** 迭代法* 使用双端队列,相当于两个栈*/
public boolean isSymmetric2(TreeNode root) {Deque<TreeNode> deque = new LinkedList<>();deque.offerFirst(root.left);deque.offerLast(root.right);while (!deque.isEmpty()) {TreeNode leftNode = deque.pollFirst();TreeNode rightNode = deque.pollLast();if (leftNode == null && rightNode == null) {continue;}if (leftNode == null || rightNode == null || leftNode.val != rightNode.val) {return false;}deque.offerFirst(leftNode.left);deque.offerFirst(leftNode.right);deque.offerLast(rightNode.right);deque.offerLast(rightNode.left);}return true;
}

100.相同的树 

这道题和上面的101对称二叉树本质上是同一道题,都是判断两颗二叉树的各个位置的节点是否相同,对称二叉树主要看同一颗树的左右两颗子树是否是相互对称的,因此需要判断左子树的内侧节点以及外侧节点与右子树的内侧节点与外侧节点是否相同,而本题主要判断两颗树相同位置的节点是否相同,本质上都是一样的,思路上也有很多相同之处。

本地依然可以使用递归和迭代两种方式解题:

递归:

依然是熟悉的递归三部曲:

  1. 判断递归的参数和返回值:
    由于本题需要判断两颗树是否相同,因此需要在递归中遍历到两颗树的所有节点,故递归的参数需要两颗树的根节点,返回值就是bool类型
public boolean isSameTree(TreeNode p, TreeNode q) {
  1. 判断递归的终止条件:

递归的终止条件有三种:

    • 遍历到的两颗树的节点都为null,返回true。
    • 遍历到的两颗树的节点只有一个为null,返回false。
    • 遍历到的两颗树的节点都不为null,但是两颗树的节点的值不同,返回false。
if (p == null && q == null) {return true;
}
// 通过上面的判断,这个判断如果为true一定是两个节点一个为null一个不为null,返回false
if (p == null || q == null) {return false;
}
if (p.val != q.val) {return false;
}
  1. 判断单次递归的逻辑:

单次递归的逻辑只有在两个节点都不为null,并且两个节点的值相同的情况下才会执行,因此单次递归的逻辑就是继续比较两个节点的子节点是否相同,这里也是和101.对称二叉树 解法不同的地方,因为101题强调两颗树的对称,因此在比较子节点时,是将左子树的左节点和右子树的右节点比较,即比较子树的外侧,以及左子树的右节点和右子树的左节点,即比较子树的内侧,而本题是比较两颗树是否相同,因此应该比较相同位置的节点是否相同,因此应该比较两个节点的左节点是否相同以及两个节点的右节点是否相同。

// 判断两个节点的左子树是否是相同的
boolean a = isSameTree(p.left, q.left);
// 判断两个节点的右子树是否是相同的
boolean b = isSameTree(p.right, q.right);
return a && b;

完整的递归代码如下:

// 递归
public boolean isSameTree(TreeNode p, TreeNode q) {if (p == null && q == null) {return true;}// 通过上面的判断,这个判断如果为true一定是两个节点一个为null一个不为null,返回falseif (p == null || q == null) {return false;}if (p.val != q.val) {return false;}// 判断左子树是否是相同的boolean a = isSameTree(p.left, q.left);// 判断右子树是否是相同的boolean b = isSameTree(p.right, q.right);return a && b;
}

迭代:

迭代法用到了与101.对称二叉树相同的思想,每次将下次需要比较的两个节点依次加入到一个队列数据结构,如果队列不为空,则拿出队列中的两个元素进行判断和比较,具体的判断逻辑和上述递归方法中的第二个步骤相同,因此直接给出代码实现:

注意:

入队的顺序必须是两个节点比较的顺序,并且两个需要比较的节点必须相邻入队。

//迭代public boolean isSameTree2(TreeNode p, TreeNode q) {// 队列Queue<TreeNode> queue = new LinkedList<>();// 需要比较的元素入队,第一次入队也可以叫为初始化队列queue.offer(p);queue.offer(q);while (!queue.isEmpty()) {// 弹出需要比较的两个节点进行比较TreeNode pNode = queue.poll();TreeNode qNode = queue.poll();if (pNode == null && qNode == null) {continue; // 都为null,跳出本次循环,比较队列中其他节点}if (pNode == null || qNode == null || qNode.val != pNode.val) {return false;}// 将需要比较的两个节点依次放入队列queue.offer(pNode.left);queue.offer(qNode.left);queue.offer(pNode.right);queue.offer(qNode.right);}return true;}

http://www.ppmy.cn/embedded/40663.html

相关文章

使用python爬取图片

使⽤ requests 库来获取⽹⻚内容&#xff0c;并⽤ BeautifulSoup 来解析HTML&#xff0c;找到所有图⽚的URL。然后&#xff0c;可以⽤ requests 再次下载这些图⽚并将它们保存到本地。 以下是⼀个简单的图⽚下载器的⽰例代码。这个脚本会下载指定⽹⻚上的所有图⽚到⼀个名为do…

5G NR 吞吐量计算 and 4G LTE 吞吐量计算

5G NR Throughput References • 3GPP TS 38.306 V15.2.0 (2018-06) ➤J : number of aggregated component carriers in a band or band combination ➤Rmax : 948/1024 • For the j-th CC, Vlayers(j) is the maximum number of layers ➤Qm(j) : Maximum modulation orde…

C++类和对象中篇

&#x1f407; &#x1f525;博客主页&#xff1a; 云曦 &#x1f4cb;系列专栏&#xff1a;[C] &#x1f4a8;路漫漫其修远兮 吾将而求索 &#x1f49b; 感谢大家&#x1f44d;点赞 &#x1f60b;关注&#x1f4dd;评论 文章目录 &#x1f4d4;前言&#x1f4d4;1、类的六个…

自动秒收录网址导航分类目录模板

自动秒收录网址导航是一个以html5css3进行开发的免费版网址自动收录模板源码。 模板特点&#xff1a;全站响应式H5网站制作技术&#xff0c;一个网站适应不同终端&#xff0c;模板支持网址导航一键采集入库&#xff0c;免规则文章资讯智能批量采集内置伪原创&#xff0c;本地化…

理解并实现区块链智能合约

理解并实现区块链智能合约是一个涉及多个技术层面的过程。智能合约是自动执行、管理区块链上交易或协议的程序。它们在满足预设条件时自动执行合约条款&#xff0c;从而减少了中间人的需要&#xff0c;并提高了透明度和效率。下面是智能合约的基本概念和实现步骤&#xff1a; …

引入 Redis

简介 Jedis Jedis 是早期的 Redis 的 Java 实现客户端&#xff0c;提供了比较全面的 Redis 命令的支持&#xff0c;其官方网址是&#xff1a;http://tool.oschina.net/uploads/apidocs/redis/clients/jedis/Jedis.html 优点&#xff1a;支持全面的 Redis 操作特性&#xff0…

mysql8.0常用语法

文章目录 开窗函数字段拆分递归关联查询 开窗函数 开窗函数 &#xff0c;可以按组查询排列数据&#xff0c;且给每一行值都返回指定的聚合值&#xff0c;语法如下&#xff1a; 开窗函数 over([PARTITION BY 分组字段(多个用,链接)] [ORDER BY 排序字段(同前)])开窗函数分为两…

5款采用AMD Instinct MI300芯片的超酷AI和HPC服务器

我们收集了戴尔科技、联想、超微和技嘉的五款超酷人工智能和高性能计算服务器&#xff0c;这些服务器使用 AMD 的 Instinct MI300 芯片&#xff0c;该芯片于几个月前推出&#xff0c;旨在挑战 Nvidia 在人工智能计算领域的主导地位。 AMD 正在凭借其 Instinct MI300 加速器芯片…