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

2024-05-07 10:44

本文主要是介绍【刷爆力扣之101.对称二叉树-100.相同的树】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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;}

这篇关于【刷爆力扣之101.对称二叉树-100.相同的树】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/967125

相关文章

spoj705( 求不相同的子串个数)

题意:求串s的不同子串的个数 解题思路:任何子串都是某个后缀的前缀,对n个后缀排序,求某个后缀的前缀的个数,减去height[i](第i个后缀与第i-1 个后缀有相同的height[i]个前缀)。 代码如下: #include<iostream>#include<algorithm>#include<stdio.h>#include<math.h>#include<cstrin

leetcode105 从前序与中序遍历序列构造二叉树

根据一棵树的前序遍历与中序遍历构造二叉树。 注意: 你可以假设树中没有重复的元素。 例如,给出 前序遍历 preorder = [3,9,20,15,7]中序遍历 inorder = [9,3,15,20,7] 返回如下的二叉树: 3/ \9 20/ \15 7   class Solution {public TreeNode buildTree(int[] pr

PHP实现二叉树遍历(非递归方式,栈模拟实现)

二叉树定义是这样的:一棵非空的二叉树由根结点及左、右子树这三个基本部分组成,根据节点的访问位置不同有三种遍历方式: ① NLR:前序遍历(PreorderTraversal亦称(先序遍历)) ——访问结点的操作发生在遍历其左右子树之前。 ② LNR:中序遍历(InorderTraversal) ——访问结点的操作发生在遍历其左右子树之中(间)。 ③ LRN:后序遍历(PostorderT

【LeetCode热题100】前缀和

这篇博客共记录了8道前缀和算法相关的题目,分别是:【模版】前缀和、【模版】二维前缀和、寻找数组的中心下标、除自身以外数组的乘积、和为K的子数组、和可被K整除的子数组、连续数组、矩阵区域和。 #include <iostream>#include <vector>using namespace std;int main() {//1. 读取数据int n = 0, q = 0;ci

牛客小白月赛100部分题解

比赛地址:牛客小白月赛100_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ A.ACM中的A题 #include<bits/stdc++.h>using namespace std;#define ll long long#define ull = unsigned long longvoid solve() {ll a,b,c;cin>>a>>b>

如何根据相同分隔符提取间隔数据?

最近遇到很多提问怎么提取字符的,而这些问题都有一个相同的特征,就是要提取的内容与内容之间,都有着相同的分隔符。当然,这种问题直接用“数据” →  “分列”功能就可以一步到位实现的,但有人喜欢折腾,而更多的人又非得指定函数公式的方法,或者更多的是要保持数据的同步性。   下面,我们就来讲讲用函数公式应该怎么实现这个提取,首先来个数据和要求,如下图,将 - 号间隔的内容依次提取到右边单元格内:

eclipse中相同变量显示变色设置

java文件的设置"Window"-"preferences"-"Java"-"Editor"-"Mark Occurrences"复选框勾选 js文件的设  置"Window"-"preferences"-"web"-"javascript"-"Mark Occurrences"复选框勾选 。

在二叉树中找到两个节点的最近公共祖先(基于Java)

如题  题解 public int lowestCommonAncestor(TreeNode root, int o1, int o2) {//记录遍历到的每个节点的父节点。Map<Integer, Integer> parent = new HashMap<>();Queue<TreeNode> queue = new LinkedList<>();parent.put(roo

数据结构--二叉树(C语言实现,超详细!!!)

文章目录 二叉树的概念代码实现二叉树的定义创建一棵树并初始化组装二叉树前序遍历中序遍历后序遍历计算树的结点个数求二叉树第K层的结点个数求二叉树高度查找X所在的结点查找指定节点在不在完整代码 二叉树的概念 二叉树(Binary Tree)是数据结构中一种非常重要的树形结构,它的特点是每个节点最多有两个子节点,通常称为左子节点和右子节点。这种结构使得二叉树在数据存储和查找等方面具

牛客小白月赛100(A,B,C,D,E,F三元环计数)

比赛链接 官方讲解 这场比较简单,ABC都很签到,D是个不太裸需要预处理的 B F S BFS BFS 搜索,E是调和级数暴力枚举,F是三元环计数。三元环考的比较少,没见过可能会偏难。 A ACM中的A题 思路: 就是枚举每个边变成原来的两倍,然后看看两短边之和是否大于第三边即可。 不能只给最短边乘 2 2 2,比如 1 4 8 这组数据,也不能只给第二短边乘 2 2 2,比