力扣刷题|226.翻转二叉树、101. 对称二叉树

news2024/11/19 19:21:32

文章目录

    • LeetCode 226.翻转二叉树
      • 题目链接🔗
      • 思路
      • 递归法
      • 迭代法
    • LeetCode 101. 对称二叉树
      • 题目链接🔗
      • 思路
      • 递归法
      • 迭代法
      • 相关题目

LeetCode 226.翻转二叉树

题目链接🔗

LeetCode 226.翻转二叉树

思路

这道题目使用前序遍历和后序遍历都可以,唯独中序遍历不方便,因为中序遍历会把某些节点的左右孩子翻转了两次!建议拿纸画一画,就理解了

那么层序遍历可以不可以呢?依然可以的!只要把每一个节点的左右孩子翻转一下的遍历方式都是可以的!

递归法

在这里插入图片描述
我们来看一下递归三部曲:

  1. 确定递归函数的参数和返回值
    参数就是要传入节点的指针,不需要其他参数了,通常此时定下来主要参数,如果在写递归的逻辑中发现还需要其他参数的时候,随时补充。

    返回值的话其实也不需要,但是题目中给出的要返回root节点的指针,可以直接使用题目定义好的函数,所以就函数的返回类型为TreeNode。

    TreeNode invertTree(TreeNode root)
    
  2. 确定终止条件
    当前节点为空的时候,就返回

    if(root == null){
    	return root;
    }
    
  3. 确定单层递归的逻辑
    因为是先前序遍历,所以先进行交换左右孩子节点,然后反转左子树,反转右子树。

    swapChildren(root);
    invertTree(root.left);
    invertTree(root.right);
    

最终完整的代码为:

class Solution {
/**
     * 前后序遍历都可以
     * 中序不行,因为先左孩子交换孩子,再根交换孩子(做完后,右孩子已经变成了原来的左孩子),
     * 再右孩子交换孩子(此时其实是对原来的左孩子做交换)
     */
    public TreeNode invertTree(TreeNode root) {

        if(root == null){
            return root;
        }

        swapChildren(root);     //中
        invertTree(root.left);  //左
        invertTree(root.right); //右
        return root;
    }

    private void swapChildren(TreeNode root) {
        TreeNode tmp = root.left;
        root.left = root.right;
        root.right = tmp;
    }
}

迭代法

如果对迭代法不清除的,可以去看二叉树的遍历

//BFS 广度优先遍历  也就是层序遍历
class Solution {
    public TreeNode invertTree(TreeNode root) {
        if (root == null) {return null;}
        ArrayDeque<TreeNode> deque = new ArrayDeque<>();
        deque.offer(root);
        while (!deque.isEmpty()) {
            int size = deque.size();
            while (size-- > 0) {
                TreeNode node = deque.poll();
                swap(node);
                if (node.left != null) deque.offer(node.left);
                if (node.right != null) deque.offer(node.right);
            }
        }
        return root;
    }

    public void swap(TreeNode root) {
        TreeNode temp = root.left;
        root.left = root.right;
        root.right = temp;
    }
}

LeetCode 101. 对称二叉树

题目链接🔗

LeetCode 101. 对称二叉树

思路

对于二叉树是否对称,要比较的是根节点的左子树与右子树是不是相互翻转的,理解这一点就知道了其实我们要比较的是两个树(这两个树是根节点的左右子树),所以在递归遍历的过程中,也是要同时遍历两棵树。

在这里插入图片描述
本题遍历只能是“后序遍历”,因为我们要通过递归函数的返回值来判断两个子树的内侧节点和外侧节点是否相等。

正是因为要遍历两棵树而且要比较内侧和外侧节点,所以准确的来说是一个树的遍历顺序是左右中,一个树的遍历顺序是右左中。

但都可以理解算是后序遍历,尽管已经不是严格上在一个树上进行遍历的后序遍历了。

递归法

递归三部曲

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

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

返回值自然是布尔类型

boolean compare(TreeNode left, TreeNode right);
  1. 确定终止条件

要比较两个结点数值相不相同,首先要把两个结点为空的情况弄清除。

结点为空的情况有:

  • 左节点为空,右节点不为空,返回false
  • 右节点为空,左节点不为空,返回false
  • 两个结点都为空,返回true

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

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

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

if(left == null && right != null) return false;
else if(left != null && right == null) return false;
else if(left == null && right == nul) return true;
else if(left.val != right.val) return false;

注意上面最后一种情况,没有使用else,而是else if, 因为我们把以上情况都排除之后,剩下的就是 左右节点都不为空,且数值相同的情况。

  1. 确定单层递归逻辑

单层递归的逻辑就是处理左右结点都不为空且数值相同的情况

  • 比较二叉树外侧是否对称:传入的是左节点的左孩子,右节点的右孩子。
  • 比较内测是否对称,传入左节点的右孩子,右节点的左孩子。
  • 如果左右都对称就返回true ,有一侧不对称就返回false 。
boolean outside = compare(left.left, right.right);  // 左子树:左、 右子树:右
boolean inside = compare(left.right, right.left);   // 左子树:右、 右子树:左 
bool isSame = outside && inside;                    // 左子树:中、 右子树:中(逻辑处理)
return isSame;

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

完整代码:

 public boolean isSymmetric1(TreeNode root) {
        return compare(root.left, root.right);
    }

    private boolean compare(TreeNode left, TreeNode right) {

        if (left == null && right != null) {
            return false;
        }
        if (left != null && right == null) {
            return false;
        }

        if (left == null && right == null) {
            return true;
        }
        if (left.val != right.val) {
            return false;
        }
        // 比较外侧
        boolean compareOutside = compare(left.left, right.right);
        // 比较内侧
        boolean compareInside = compare(left.right, right.left);
        return compareOutside && compareInside;
    }

迭代法

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

这里我们可以使用队列来比较两个树(根节点的左右子树)是否相互翻转

使用普通队列
在这里插入图片描述

 public boolean isSymmetric(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.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. 相同的树

class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
        return compare(p, q);
    }

    private boolean compare(TreeNode left, TreeNode right){
        if(left == null && right == null){
            return true;
        }
        
        if(left == null || right == null || left.val != right.val){
            return false;
        }

        boolean leftside = compare(left.left, right.left);
        boolean rightside = compare(left.right, right.right);
        return leftside && rightside;
    }
}

572. 另一棵树的子树

class Solution {
    public boolean isSubtree(TreeNode root, TreeNode subRoot) {
        if(root == null){
            return false;
        }
        if(root.val == subRoot.val && compare(root, subRoot)){
            return true;
        }

        return isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot);
    }

    boolean compare(TreeNode root, TreeNode node){
        if(root == null && node == null){
            return true;
        }

        if(root == null || node == null || root.val != node.val){
            return false;
        }

        return compare(root.left, node.left) && compare(root.right, node.right);
    }
}

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

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

相关文章

PVID和VID相关小知识

欢迎来到东用知识小课堂&#xff01;1.PVID和VID的区别PVID和VID经常出现于二、三层交换机里&#xff0c;很多时候由于PVID和VID的设置不合理&#xff0c;造成VLAN划分变得混乱。一般你去超市买东西有个扫描设备扫描一下商品上的标签&#xff0c;然后价格就会出现。商品上的标签…

分布式锁与数据库悲观、乐观锁

分布式锁 什么是分布式锁 要介绍分布式锁&#xff0c;首先要提到与分布式锁相对应的是线程锁、进程锁。 1.线程锁 主要用来给方法、代码块加锁。当某个方法或代码使用锁&#xff0c;在同一时刻仅有一个线程执行该方法或该代码段。线程锁只在同一JVM中有效果&#xff0c;因为…

Redis主从复制与读写分离

1、为什么要主从复制、读写分离Redis在作为缓存的时候&#xff0c;随着项目访问量的增加&#xff0c;对Redis服务器的操作也越加频繁&#xff0c;虽然Redis读写速度都很快&#xff0c;但是一定程度上也会造成一定的延时&#xff0c;甚至出现宕机的可能性&#xff0c;这时候就出…

如何使用知行之桥搭建SFTPServer

知行之桥EDI系统同时支持SFTP Server和SFTP Client功能&#xff0c;既可以作为SFTP Server供多个Client连接&#xff0c;也可以作为Client连接多个Server。无论是作为SFTP Server还是SFTP Client&#xff0c;都只需要简单的配置即可实现。 SFTP Server的特性包括一下几点&…

【React全家桶】react路由

react路由5.1. 路由的简介5.2 路由的基本使用5.3 路由组件与一般组件5.4 NavLink及其封装5.5 Switch5.6 路由的模糊匹配与严格匹配5.7 Redirect重定向5.8 向路由组件传递参数5.9 编程式路由导航5.10withRouter的使用5.12 BrowserRouter与HashRouter的区别5.1. 路由的简介 单页W…

代码随想录--二叉树章节总结 Part III

代码随想录–二叉树章节总结Part III 1.Leetcode106 从中序与后序遍历序列构造二叉树 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 解题思路…

【Go基础】并发编程

文章目录1. 并发模型2. Goroutine的使用3. Channel的同步与异步4. 并发安全性5. 多路复用6. 协程泄漏7. 协程管理1. 并发模型 任何语言的并行&#xff0c;到操作系统层面&#xff0c;都是内核线程的并行。同一个进程内的多个线程共享系统资源&#xff0c;进程的创建、销毁、切…

【监控开发】jps命令怎么远程调用另一个IP的机器,jstatd服务支持

jsp命令远程调用咩有Linux服务器启动jstatd服务的时候Linux服务器如何启动jstatd服务1.查找jdk所在目录2.在jdk的bin目录下创建文件jstatd.all.policy3.给这个文件赋权4.这个文件写入安全配置&#xff0c;赋值粘贴即可5.启动jstatd服务6.查看是否启动成功再去另外一台服务器调用…

第一章:Go语言为并发而生

在早期 CPU 都是以单核的形式顺序执行机器指令。Go语言的祖先C语言正是这种顺序编程语言的代表。顺序编程语言中的顺序是指&#xff1a;所有的指令都是以串行的方式执行&#xff0c;在相同的时刻有且仅有一个 CPU 在顺序执行程序的指令。 随着处理器技术的发展&#xff0c;单核…

C语言深度解剖-关键字(4)

目录 signed、unsigned 关键字补充内容 关于大端和小端 大小端存储数据方式 判断大小端 深入理解数据存储 练习&#xff1a; 写在最后&#xff1a; signed、unsigned 关键字补充内容 关于大端和小端 我们通过在内存中存储一个值&#xff0c; 用于观察数据在内存中的存…

Python连接Liunx中mysql数据库-保姆级教程

首先确保你的liunx中已经安装好了mysql数据库如果没有安装mysql数据库看这篇文章Centos6从零开始安装mysql和tomcat后台环境&#xff0c;并成功部署Tomcat项目图文详细过程 python连接Liunx中mysql数据库进行增删改查liunx中相关环境改变Python中连接liunx中的mysql数据库在Nav…

上班第一件事:马上卸载这个恶心的软件!

一上班就被Notepad给恶心到了。“如果不同意政治观点&#xff0c;就在你的源码中添加随机字符。”这个Notepad作者侯今吾真是把自己当做大人物了啊&#xff1f;&#xff01;率性而为&#xff0c;根本不再考虑用户的感受了。 这个Twitter帖子很快就被一片骂声淹没&#xff0c;这…

【每日CSS3代码】

1-1 两栏布局【1/27】 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevi…

OpenJudge NOI 2.4 8463:Stupid cat Doge

【题目链接】 OpenJudge NOI 2.4 8463:Stupid cat & Doge 【题目考点】 1. 递归 2. 分形图 【解题思路】 解法1&#xff1a;递归 1级正方形边长是212^121&#xff0c;2级正方形边长为222^222&#xff0c;。。。&#xff0c;n级正方形边长为2n2^n2n&#xff0c;总格子…

autojs画六边形

牙叔教程 简单易懂 界面基础代码 "nodejs ui"; require("rhino").install(); const ui require("ui"); class MainActivity extends ui.Activity {constructor() {super();}get layoutXmlFile() {return "layout.xml";}onContentVi…

高效学 C++|继承与组合

继承是面向对象程序设计的重要特性之一。作为面向对象的编程语言&#xff0c;C语言也自然支持这个特性。继承是代码复用的基本方法之一&#xff0c;也是接口和复用设计的关键。本文介绍继承的含义和继承与组合的关系。 01、继承的含义 面向对象程序设计通过将问题域中的事物抽…

Web 应用程序的文件系统写入能力

介绍 NodeJS 之前&#xff0c;JS 操作文件只能通过 HTML <input type"file"> 元素或 XMLHttpRequest&#xff08;或之后的 fetch&#xff09;&#xff0c;来对本地文件进行一些浏览和上传操作。NodeJS 给予了 JS 操作系统底层 API 的能力&#xff0c;但这只能…

章节7 查看和处理文件内容

7-查看和处理文件内容 文本文件 ASCII、UTF-8、Unicode、ANSItxt、xml、conf、properties、yml等配置文件、日志文件、源代码 二进制文件 可执行文件、图片、音频、视频 cat 全拼&#xff1a;concatenate [kənˈkt(ə)nˌeɪt] 连接 格式&#xff1a;cat 文件名 more/…

eyeurl—一款网页批量截图工具

eyeurl使用说明 开发说明 eyeurl由作者&#xff1a;云小书 开发&#xff0c;源于日常渗透测试中&#xff0c;信息收集到的url过多&#xff0c;挨个打开查看比较繁琐&#xff0c;且效率极低&#xff0c;网上有大佬开发的eyewitness&#xff0c;且ui布局各方面都比较完善&#…

sadserver 题目思路概述

背景 从 阮一峰老师的博客 了解到 sadserver 可以在线挑战一些 linux 指令相关问题&#xff08;整体难度一般&#xff0c;但做题体验不错&#xff0c;有提示&#xff09;&#xff0c;这里将目前网站提供的的16道题进行简单解答&#xff0c;提供思路和相关指令 本文csdn 博客地…