二叉树-31-37对称二叉树

news2024/11/15 16:30:24

31. 对称的二叉树在这里插入图片描述在这里插入图片描述

递归:

把原问题化成更小规模的问题,并且具有相同的问题性质,重复调用本身函数
二叉树的递归,是将某个节点的左子树、右子树看成一颗完整的树,那么对于子树的访问或者操作就是对于原树的访问或者操作的子问题,因此可以自我调用函数不断进入子树。

  • 终止条件: 当进入子问题的两个节点都为空,说明都到了叶子节点,且是同步的,因此结束本次子问题,返回true;当进入子问题的两个节点只有一个为空,或是元素值不相等,说明这里的对称不匹配,同样结束本次子问题,返回false。
  • 返回值: 每一级将子问题是否匹配的结果往上传递。
  • 本级任务: 每个子问题,需要按照上述思路,“根左右”走左边的时候“根右左”走右边,“根左右”走右边的时候“根右左”走左边,一起进入子问题,需要两边都是匹配才能对称。
import java.util.*;
/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;
    public TreeNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    boolean isSymmetrical(TreeNode pRoot) {
        return resu(pRoot,pRoot);        
    }
    boolean resu(TreeNode p1, TreeNode p2){
        if(p1==null&&p2==null){
            return true;
        }
        if(p1==null||p2==null||p1.val!=p2.val) return false;//注意p1.val!=p2.val一定要放在或的最后一个
        return resu(p1.left, p2.right)&&resu(p1.right, p2.left);
    }
}

注意p1.val!=p2.val一定要放在或的最后一个,否则当有一个为null时就会出现异常。

时间复杂度和空间复杂度都是O(N)

32.合并二叉树

在这里插入图片描述
递归

import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 * }
 */

public class Solution {
    /**
     * 
     * @param t1 TreeNode类 
     * @param t2 TreeNode类 
     * @return TreeNode类
     */
    public TreeNode mergeTrees (TreeNode t1, TreeNode t2) {
        // write code here
        if(t1==null) return t2;
        if(t2==null) return t1;
        TreeNode head = new TreeNode(t1.val+t2.val);
        head.left = mergeTrees(t1.left,t2.left);
        head.right = mergeTrees(t1.right,t2.right);
        return head;
    }
}

时间复杂度和空间复杂度都是O(N)

33. 二叉树的镜像

在这里插入图片描述
递归的话,每次都交换节点的左右子树

import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 *   public TreeNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param pRoot TreeNode类 
     * @return TreeNode类
     */
    public TreeNode Mirror (TreeNode pRoot) {
        // write code here
        if(pRoot==null) return null;
        TreeNode node = pRoot.left;
        pRoot.left = pRoot.right;
        pRoot.right = node;
        Mirror(pRoot.left);
        Mirror(pRoot.right);
        return pRoot;
    }
}

时间复杂度和空间复杂度都是O(N),没找到空间复杂度为O(1)的解法。
递归本质上是深搜,广搜可以用队列或者栈来解决。思路是每次出堆、栈的元素的时候,交换该节点的左右节点
用队列

import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 *   public TreeNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param pRoot TreeNode类 
     * @return TreeNode类
     */
    public TreeNode Mirror (TreeNode pRoot) {
        // write code here
        Queue<TreeNode> q = new ArrayDeque<>();
        if(pRoot==null) return null;
        q.offer(pRoot);
        while(!q.isEmpty()){
            TreeNode node = q.poll();
            TreeNode tmp = node.left;
            node.left = node.right;
            node.right = tmp;
            if(node.left!=null) q.offer(node.left);
            if(node.right!=null) q.offer(node.right);
        }
        return pRoot;
    }
}

用栈:

import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 *   public TreeNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param pRoot TreeNode类 
     * @return TreeNode类
     */
    public TreeNode Mirror (TreeNode pRoot) {
        // write code here
        Stack<TreeNode> q = new Stack<>();
        if(pRoot==null) return null;
        q.push(pRoot);
        while(!q.isEmpty()){
            TreeNode node = q.pop();
            TreeNode tmp = node.left;
            node.left = node.right;
            node.right = tmp;
            if(node.left!=null) q.push(node.left);
            if(node.right!=null) q.push(node.right);
        }
        return pRoot;
    }
}

只要全都翻转一遍即可,至于先后顺序不重要,所以这里用队列和栈是完全一样的,时间空间都是O(N)

34. 判断是不是二叉搜索树

第一次用递归true和false的方法,只能判断当前节点和左右子节点的关系,不能保证所有的子孙节点。
思路:用中序遍历,存成数组后判断数组是不是递增的。

import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 *   public TreeNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param root TreeNode类 
     * @return bool布尔型
     */
    public boolean isValidBST (TreeNode root) {
        // write code here
        ArrayList<Integer> list = new ArrayList<>();
        inorder(list,root);
        for(int i = 0; i < list.size()-1; i++){
            if(list.get(i) >= list.get(i+1)) return false;
        }
        return true;

    }
    public void inorder(ArrayList<Integer> list, TreeNode root){
        if(root==null) return ;
        inorder(list,root.left);
        list.add(root.val);
        inorder(list,root.right);
        return;
    }
}

另一种递归做法
step 1:首先递归到最左,初始化maxLeft与pre。
step 2:然后往后遍历整棵树,依次连接pre与当前节点,并更新pre。
step 3:左子树如果不是二叉搜索树返回false。
step 4:判断当前节点是不是小于前置节点,更新前置节点。
step 5:最后由右子树的后面节点决定。
这样不需要额外的数组存,不需要每次都遍历完,只要每次遍历到的时候判断和前一个节点值的大小即可

import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 *   public TreeNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param root TreeNode类 
     * @return bool布尔型
     */
    int pre = Integer.MIN_VALUE;
    public boolean isValidBST (TreeNode root) {
        // write code here
        if(root==null) return true;
        //先判断左子树
        if(!isValidBST(root.left)) return false;
        if(root.val<=pre) return false;
        pre = root.val;
        //右子树
        return isValidBST(root.right);
    }

}

35. 判断是不是完全二叉树

用队列实现的层次遍历,用LinkedList可以存储null,标记第一次出现null,之后再遇到就返回false

import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 *   public TreeNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param root TreeNode类 
     * @return bool布尔型
     */
    public boolean isCompleteTree (TreeNode root) {
        // write code here
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);   
        boolean flag = false;
        while(!q.isEmpty()){
            TreeNode node = q.poll();
            if(node==null){
                flag = true;
                continue;
            }
            if(flag) return false;
            q.offer(node.left);
            q.offer(node.right);                          
        }
        return true;   
    }
}

ArrayDeque类是可变数组的实现,不可存储null。LinkedList是线性表的实现,实现了线性表的所有操作,可存储null
这里不能用ArrayDeque!!!

36. 判断是不是平衡二叉树

在这里插入图片描述
在求树的深度的基础上进行改进
二叉树求树的深度的代码:

public int TreeDepth(TreeNode root) {
        if(root == null)
            return 0;
        int l = TreeDepth(root.left);
        int r = TreeDepth(root.right);
        return Math.max(l,r)+1;
    }

在这个基础上加上判断左右子树高度差超过1:

    boolean isBalanced = true; // 默认标记为true
    public boolean IsBalanced_Solution(TreeNode root) {
        TreeDepth(root);
        return isBalanced;
    }

public int TreeDepth(TreeNode root) {
        if(root == null)
            return 0; // 递归终止
        int l = TreeDepth(root.left);
        int r = TreeDepth(root.right);

        if(Math.abs(l-r) > 1){
            isBalanced = false;  // 不是平衡树
        }

        return Math.max(l,r)+1; // 求深度
    }

但是这样总是会遍历完所有的节点,我们可以进行改进,边求深度边判断

public class Solution {
    public boolean IsBalanced_Solution(TreeNode root) {
        return depth(root)!=-1;
        
    }
    public int depth(TreeNode root){
        if (root==null) return 0;
        int l = depth(root.left);
        if(l==-1) return -1;
        int r = depth(root.right);
        if(r==-1) return -1;
        if(Math.abs(l-r)>1) return -1;
        return Math.max(l,r)+1;       
    }
}

时间和空间复杂度都是O(N)

37. 二叉搜索树的最近公共祖先

在这里插入图片描述

import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 *   public TreeNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param root TreeNode类 
     * @param p int整型 
     * @param q int整型 
     * @return int整型
     */
    public int lowestCommonAncestor (TreeNode root, int p, int q) {
        // write code here
        //第一次进入不同的分支就找到了
        if((p<root.val&&root.val<q)||(q<root.val&&root.val<p)) return root.val;
        if(p<root.val&&q<root.val) return lowestCommonAncestor(root.left,p,q);
        if(p>root.val&&q>root.val) return lowestCommonAncestor(root.right,p,q);
        return root.val;
    }
}

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

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

相关文章

HTML如何制作音乐网站(如何搭建个人音乐网页)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

Java毕业设计 JSP+MySQL幼儿园信息管理系统

幼儿园网站就是幼儿园的“商标”,在网站上可以看出一所幼儿园的特色和个性,在这个信息时代,建立属于自己的幼儿园网站是最直接的宣传手段。而就目前的幼儿园信息管理系统来说,有很多功能都是华而不实的,不能很好的与幼儿园日常工作相结合,容易导致日常工作出现异常。本系统的题…

【HDU No. 4417】 超级马里奥 Super Mario

【HDU No. 4417】 超级马里奥 Super Mario 杭电OJ 题目地址 【题意】 可怜的公主陷入困境&#xff0c;马里奥需要拯救他的情人。把通往城堡的道路视为一条线&#xff08;长度为n &#xff09;&#xff0c;在每个整数点i 上都有一块高度为hi 的砖&#xff0c;马里奥可以跳的最…

【博客552】git auto-merge原理以及auto-merge的不同模式

git auto-merge原理 1、merge 常见误区 1、git merge 是用时间先后决定merge结果的&#xff0c;后面会覆盖前面的? 答 &#xff1a;git 是分布式的文件版本控制系统&#xff0c;在分布式环境中时间是不可靠的&#xff0c;git是靠三路合并算法进行合并的。 2、git merge 只…

电脑装了w10没有w7流畅怎么办?

如果我们对自己的电脑进行了系统的重装&#xff0c;在电脑装了win10系统之后发现没有win7流畅的话&#xff0c;很多小伙伴不知道是什么情况应该怎么解决。 那么据微点阅读小编所知可能是我们电脑硬件设施的不兼容所导致的。我们可以在官网上查看win10系统的配置要求是否符合自…

一文带你深入理解【Java基础】· 泛型

写在前面 Hello大家好&#xff0c; 我是【麟-小白】&#xff0c;一位软件工程专业的学生&#xff0c;喜好计算机知识。希望大家能够一起学习进步呀&#xff01;本人是一名在读大学生&#xff0c;专业水平有限&#xff0c;如发现错误或不足之处&#xff0c;请多多指正&#xff0…

Arduino开发实例-DIY风速测量及显示

DIY风速测量及显示 1、应用介绍 本次实例将使用一款具有 NPN 脉冲输出的数字风速计传感器。 NPN脉冲输出风速计效果好,性价比高。另外它仅在 5V 电源下工作。 在本次实例中,将此风速计传感器与 Arduino 板和 0.96 英寸 OLED 显示屏连接。 OLED显示屏将以米/秒为单位显示风速…

[附源码]计算机毕业设计基于SpringBoot的酒店预订系统设计与实现

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

​AAAI 2023 | 基于历史对比学习的时序知识图谱推理

©PaperWeekly 原创 作者 | 徐奕单位 | 上海交通大学Acemap研究方向 | 数据挖掘论文标题&#xff1a;Temporal Knowledge Graph Reasoning with Historical Contrastive Learning论文链接&#xff1a;https://arxiv.org/abs/2211.10904代码链接&#xff1a;https://github…

Elasticsearch好用查询插件分享

以前我常用的ES查询工具是Head&#xff0c;作为插件形式在浏览器中运行&#xff0c;挺方便的&#xff0c;后来发现head不太好用&#xff0c;比如在数据浏览的时候&#xff0c;不小心就点击了两个索引&#xff0c;背景色设置的还不够明显&#xff0c;比较容易看错数据的。于是想…

git中rebase和merge的区别

介绍 Merge和Rebase是合并两个分支的操作。都是checkout到某个分支上&#xff0c;然后将别的分支合并&#xff08;变基&#xff09;到本分支上。 注意&#xff1a;本分支&#xff08;head指向的分支&#xff0c;或者经过checkout后的分支&#xff09;会变化&#xff0c;而别的…

在Linux上部署Servlet程序

目录 一、部署环境 1、安装JDK 2、安装Tomcat 3、安装MySQL 二、部署程序 1、构造云服务器上的数据库 2、打包程序 3、部署程序 一、部署环境 为了部署我们自己的web程序&#xff0c;首先需要在Linux上安装程序所依赖的环境~ 1、安装JDK 直接使用yum安装openjdk&…

小程序云开发笔记二

小程序云开发笔记二一、读取数据库播放列表将数据显示到界面二、上拉加载三、上拉刷新四、云函数路由优化tcb-router案例&#xff1a;点击两个按钮调用同一个云函数将music中写成koa风格的云函数五、事件冒泡组件参数properties和data一、读取数据库播放列表将数据显示到界面 …

java同步方法

观看此文 首先 你要了解 java的同步锁 如果不了解 可以观看我的文章 java 同步锁synchronized 解决线程共享数据重复操作问题 那么 从下图 我们可以看到 逻辑代码上被绑了一个同步锁 但这个其实大可以写成一个函数 看起来会美观便捷很多 同步方法的格式如下 修饰符 synchro…

git switch 命令详解

1. 前言 2. switch 创建分支 3. switch 切换分支 1. 前言 checkout 命令具有 分支的管理 和 文件的恢复 两个核心功能&#xff0c;功能较多、不够准确。在 git 2.23 版本中新增了 switch 和 restore命令&#xff0c;用于替代 checkout 命令&#xff0c;进而分化 checkout 命…

(附源码)springboot大学生竞赛管理平台 毕业设计

题 目 springboot大学生竞赛管理平台 目 录 摘要 1 1 绪论 1 1.1选题意义 1 1.2国内外研究现状 1 1.3系统开发技术的特色 4 1.4论文结构与章节安排 4 2 大学生竞赛管理平台分析 5 2.1 可行性分析 5 2.2 系统流程分析 6 2.2.1数据增加流程 7 2.3.2数据修改流程 7 2.3.3数据删…

java面向对象----封装 构造器

目录 封装和隐藏 为什么需要封装&#xff1f; 信息的封装和隐藏 四种访问权限修饰符 构造器(构造方法) 构造器的特征 语法格式&#xff1a; 构造器重载 构造器重载举例 属性赋值过程 JavaBean UML类图 关键字—this this是什么&#xff1f; 使用this&#xff0c;…

计算机网络笔记2 物理层

计算机网络系列笔记目录&#x1f447; 计算机网络笔记6 应用层计算机网络笔记5 运输层计算机网络笔记4 网络层计算机网络笔记3 数据链路层计算机网络笔记2 物理层计算机网络笔记1 概述 本文目录文章前言 &#x1f497;一、物理层概述&#x1f60a;二、物理层的传输媒体&#x…

Spring源码该如何阅读?十年架构师带来的Spring源码解析千万不要错过!

写在前面 最近学习了一句话&#xff0c;感觉自己的世界瞬间明朗&#xff0c;不再那么紧张焦虑恐慌&#xff0c;同样推荐给大家&#xff0c;希望我们都终有所得。 “如果一个人不是发自内心地想要做一件事情&#xff0c;那么&#xff0c;他是无法改变自己的人生的。” 同样这句…

4. 死信队列

二八佳人体似酥&#xff0c;腰间仗剑斩愚夫。虽然不见人头落&#xff0c;暗里教君骨髓枯。 死信 概念 先从概念解释上搞清楚这个定义&#xff0c;死信&#xff0c;顾名思义就是无法被消费的消息&#xff0c;字面意思可以这样理 解&#xff0c;一般来说&#xff0c;producer 将…