java数据结构与算法刷题-----LeetCode572. 另一棵树的子树(经典题,树字符串化KMP)

java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完):https://blog.csdn.net/grd_java/article/details/123063846

文章目录

    • 1. 暴力求解,深度优先
    • 2. KMP算法进行串匹配

在这里插入图片描述

1. 暴力求解,深度优先

解题思路:时间复杂度O(s*t)其中s是树的结点个数,t是子树的结点个数。空间复杂度O(max(ds,dt))其中ds是树的深度,dt是子树的深度
  1. 我们先对整个树深度优先遍历
  2. 每个结点都与子树的根节点进行比对
  3. 如果对上了,就以当前结点为根节点,进行和子树的深度优先遍历,看看是否一一对应
  4. 对应上就返回true,没对应上就继续深度优先遍历。直到整个树遍历完成
代码

在这里插入图片描述

class Solution {
    public boolean isSubtree(TreeNode root, TreeNode subRoot) {
        if(root == null && subRoot == null) return true;//如果都为null,就无需找子树了
        else if(root == null || subRoot == null) return false;//如果有一个为null,另一个不是null,肯定不是子树
        //先进行深度优先遍历,直接比对当前结点,如果能对上就可以省下很多时间
        //遍历到底时,再去isSameTree方法中,判断以当前root为根的子树,是否和subRoot是一样的
        else return isSubtree(root.left,subRoot) || isSubtree(root.right,subRoot)||isSameTree(root,subRoot);
    }
    //深度优先判断是否是相同的树
    public boolean isSameTree(TreeNode root,TreeNode subRoot){
        if(root == null && subRoot == null) return true;
        if(root == null || subRoot == null) return false;
        if(root.val == subRoot.val){
            return isSameTree(root.left,subRoot.left) && isSameTree(root.right,subRoot.right);
        }
        return false;
    }
}

2. KMP算法进行串匹配

KMP算法https://blog.csdn.net/grd_java/article/details/136107363
解题思路:时间复杂度O(s+t),空间复杂度O(s+t)
  1. 生成两颗树的遍历序列,以类似如下的形式:(下面形式是广度(层序)遍历序列,需要额外空间辅助,所以我们放弃)
    在这里插入图片描述
  2. 为了效率和更少的空间,我们使用广度优先遍历。那么就需要两个不同的值,来表示某结点左子树为空,和右子树为空的情况。
  3. 同样为了效率,我们不使用字符串比较,选用int型容器,比如int型的链表来生成匹配串
  4. 那么null如何来表示呢?
  1. 我们可以规定两个值,来分别表示左子树为null和右子树为null的情况
  2. 这里我选择先找到树中最大值max,然后令max+1表示左子树为空情况,max+2表示右子树为空情况
  1. 生成两颗树的匹配串后,让大树作为主字符串,要匹配的子树作为要匹配的子串,改编KMP算法,如果匹配成功,说明树中可以匹配到子树
代码:leetcode的特色之一就是,更优的算法,有时因为使用程序自带的特殊容器(比如Java中的List),因为这些容器初始化比较耗时间,反而耗时更高。但是实际工作场景,一旦数据量起来,肯定是这个算法优于上面的暴力解法的。

在这里插入图片描述

class Solution {
    List<Integer> sOrder = new ArrayList<Integer>();//用来保存s树的遍历结果,主串
    List<Integer> tOrder = new ArrayList<Integer>();//保存t树,匹配串
    
    int maxElement, lNull, rNull;//maxElement保存两颗树中最大值,lNull为左子树为空的标记,rNull为右子树为空
    //此方法获取树中最大值,深度优先
    public void getMaxElement(TreeNode t) {
        if (t == null) return;
        maxElement = Math.max(maxElement, t.val);
        getMaxElement(t.left);
        getMaxElement(t.right);
    }
    //此方法生成树的遍历字符串,其中,左右子树为null的,使用lNull和rNull填充
    public void getDfsOrder(TreeNode t, List<Integer> tar) {
        if (t == null) return;
        
        tar.add(t.val);//填充当前值
        //如果左子树为null填充lNull,否则继续遍历左子树
        if (t.left != null) getDfsOrder(t.left, tar);
        else tar.add(lNull);
        //右子树不为null继续遍历右子树,否则填充rNull
        if (t.right != null) getDfsOrder(t.right, tar);
        else tar.add(rNull);
    }
    //入口方法,1.获取树最大值max,并令max+1作为lNull,max+2作为rNull
    //2. 获取两颗树的遍历串。 3. kmp算法进行匹配
    public boolean isSubtree(TreeNode s, TreeNode t) {
        maxElement = Integer.MIN_VALUE;
        //获取两颗树中的最大值
        getMaxElement(s);
        getMaxElement(t);
        //则最大值+1和+2是树中绝对不存在的两个值
        lNull = maxElement + 1;//最大值+1作为左子树为空的填充串
        rNull = maxElement + 2;//最大值+2为右子树为空
        //获取两颗树的遍历串
        getDfsOrder(s, sOrder);
        getDfsOrder(t, tOrder);
        //通过kmp算法
        return kmp();
    }
    //kmp算法,如果匹配到子串,说明树中可以匹配到t这颗子树
    public boolean kmp() {
        int sLen = sOrder.size(), tLen = tOrder.size();
        int[] fail = new int[tOrder.size()];
        fail[0] = 0;
        for (int i = 1, j = 0; i < tLen; ++i) {
            while (j > 0 && !(tOrder.get(i).equals(tOrder.get(j)))) j = fail[j-1];
            if (tOrder.get(i).equals(tOrder.get(j))) ++j;
            fail[i] = j;
        }
        for (int i = 0, j = 0; i < sLen; ++i) {
            while (j > 0 && !(sOrder.get(i).equals(tOrder.get(j)))) j = fail[j-1];
            if (sOrder.get(i).equals(tOrder.get(j))) ++j;
            if (j == tLen) return true;
        }
        return false;
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IPO观察丨“闷头做手机”的龙旗科技,如何拓宽价值边界?

提到手机代工&#xff0c;许多人会想起依靠iPhone订单发家的富士康。但近年来&#xff0c;随着国内智能手机供应链愈发成熟&#xff0c;龙旗科技、闻泰科技和华勤技术等一批国产手机代工厂快速崛起&#xff0c;业绩强劲增长之余&#xff0c;还迈进了二级市场。 比如&#xff0…

Home Assistant:基于Python的智能家居开源系统详解

Home Assistant&#xff1a;基于Python的智能家居开源系统详解 在数字化和智能化的时代&#xff0c;智能家居系统成为了现代家庭的新宠。它们能够让我们更加方便地控制家中的各种设备&#xff0c;实现自动化和个性化的居住体验。其中&#xff0c;Home Assistant作为一款基于Pyt…

国际光伏展

国际光伏展即国际光伏产业展览会&#xff0c;是全球范围内最具规模和影响力的光伏产业展览会之一。光伏展是一个专门展示和推广光伏技术和产品的平台&#xff0c;汇聚了全球各类光伏企业、研究机构和专家学者&#xff0c;是光伏行业交流、合作和发展的重要场所。 国际光伏展通常…

备战蓝桥杯---状态压缩DP基础1之棋盘问题

它只是一种手段&#xff0c;一种直观而高效地表示复杂状态的手段。 我们先来看一道比较基础的&#xff1a; 直接DFS是肯定不行&#xff0c;我们发现对某一行&#xff0c;只要它前面放的位置都一样&#xff0c;那么后面的结果也一样。 因此我们考虑用DP&#xff0c;并且只有0/…

【InternLM 实战营笔记】基于 InternLM 和 LangChain 搭建你的知识库

准备环境 bash /root/share/install_conda_env_internlm_base.sh InternLM升级PIP # 升级pip python -m pip install --upgrade pippip install modelscope1.9.5 pip install transformers4.35.2 pip install streamlit1.24.0 pip install sentencepiece0.1.99 pip install a…

吴恩达机器学习笔记十四 多输出的分类 多类和多标签的区别 梯度下降优化 卷积层

这里老师想讲的是multiclass classification和multilable classification的区别&#xff0c;下面是我从其他地方找到的说法: Multiclass classification 多类分类 意味着一个分类任务需要对多于两个类的数据进行分类。比如&#xff0c;对一系列的橘子&#xff0c;苹果或者梨的…

大数据毕业设计之前端04:管理系统为什么要自己实现图标组件

关键字&#xff1a;BuildAdmin、Icon、图标、Vue、ElementUI 前言 说到图标&#xff0c;在BuildAdmin中用到的地方很多。比如上一篇中的折叠图标&#xff0c;还有菜单栏图标、导航菜单栏图标等。常见的图标有&#xff1a;ElementUI图标、font-awesome、iconfont阿里图标以及本…

vscode+remote突然无法连接服务器以及ssh连接出问题时的排错方法

文章目录 设备描述状况描述解决方法当ssh连接出问题时的排错方法 设备描述 主机&#xff1a;win11&#xff0c;使用vscode的remote-ssh插件 服务器&#xff1a;阿里云的2C2GUbuntu 22.04 UFIE 状况描述 之前一直使用的是vscode的remote服务&#xff0c;都是能够正常连接服务…

day03-Vue-Element

一、Ajax 1 Ajax 介绍 1.1 Ajax 概述 概念&#xff1a;Asynchronous JavaScript And XML&#xff0c;异步 的 JavaScript 和 XML。 作用&#xff1a; 数据交换&#xff1a;通过 Ajax 可以给服务器发送请求&#xff0c;并获取服务器响应的数据。异步交互&#xff1a;可以在 不…

吴恩达机器学习笔记:第5周-9 神经网络的学习(Neural Networks: Learning)

目录 9.1 代价函数 9.1 代价函数 首先引入一些便于稍后讨论的新标记方法&#xff1a; 假设神经网络的训练样本有&#x1d45a;个&#xff0c;每个包含一组输入&#x1d465;和一组输出信号&#x1d466;&#xff0c;&#x1d43f;表示神经网络层数&#xff0c;&#x1d446;&…

TypeScript 哲学 - everyday Type

1、 2、TypeScript a structurally typed type system. 3、 type vs interface 3、literal reference 4、non-null assertion operator

MFC web文件 CHttpFile的使用初探

MFC CHttpFile的使用 两种方式&#xff0c;第一种OpenURL&#xff0c;第二种SendRequest&#xff0c;以前捣鼓过&#xff0c;今天再次整结果发现各种踩坑&#xff0c;好记性不如烂笔头&#xff0c;记录下来。 OpenURL 这种方式简单粗暴&#xff0c;用着舒服。 try {//OpenU…

《从0开始搭建实现apollo9.0》系列三 CANBUS模块解读

二、CANBUS代码 1、canbus模块的软件架构如下&#xff1a; 主要输入输出 输入&#xff1a;apollo::control::ControlCommand | 控制指令 输出&#xff1a; /apollo/chassis | apollo::canbus::Chassis | 车辆底盘信息接口数据&#xff0c;包括车辆速度、方向盘转角、档位、底盘…

[剪藏] - 瑞萨收购Altium!

2024年2月15日消息&#xff0c;瑞萨电子公司近日表示计划以每股68.50澳元&#xff0c;总额 91 亿澳元&#xff08;约合 59 亿美元&#xff09;收购 PCB 设计软件公司 Altium的所有流通股&#xff08;企业价值为88亿澳元&#xff09;&#xff0c;此举不禁让人联想到西门子 2017 …

物联网与智慧城市:科技驱动下的城市智能化升级之路

一、引言 随着科技的不断进步和城市化进程的加速&#xff0c;物联网与智慧城市的结合已经成为推动城市智能化升级的关键力量。物联网技术以其强大的连接和数据处理能力&#xff0c;为智慧城市的建设提供了无限可能。本文旨在探讨物联网如何助力智慧城市的构建&#xff0c;以及…

Kali Linux 安装 + 获取 root 权限 + 远程访问

一、什么是Kali kali是linux其中一个发行版&#xff0c;基于Debian&#xff0c;前身是BackTrack&#xff08;简称BT系统&#xff09;。kali系统内置大量渗透测试软件&#xff0c;可以说是巨大的渗透系统&#xff0c;涵盖了多个领域&#xff0c;如无线网络、数字取证、服务器、密…

Unity(第二十二部)官方的反向动力学一般使用商城的IK插件,这个用的不多

反向动力学&#xff08;Inverse Kinematic&#xff0c;简称IK&#xff09;是一种通过子节点带动父节点运动的方法。 正向动力学 在骨骼动画中&#xff0c;大多数动画是通过将骨架中的关节角度旋转到预定值来生成的&#xff0c;子关节的位置根据父关节的旋转而改变&#xff0c;这…

【Vue3】CSS 新特性

:slotted <template> <!-- App.vue--><Son ><div class"a">我要插入了</div></Son> </template><script setup lang"ts"> import Son from ./components/Son.vue </script><style></sty…

day10_日志模块AOP

文章目录 1 记录操作日志1.1 记录日志的意义1.2 日志数据表结构1.3 记录日志思想1.4 切面类环境搭建1.4.1 日志模块创建1.4.2 Log1.4.3 OperatorType1.4.4 LogAspect1.4.5 EnableLogAspect1.4.6 测试日志切面类 1.5 保存日志数据1.5.1 SysOperLog1.5.2 LogAspect1.5.3 AsyncOpe…

Android T 远程动画显示流程其三——桌面侧动画启动到系统侧结束流程

前言 接着前文分析Android T 远程动画显示流程其二 我们通过IRemoteAnimationRunner跨进程通信从系统进程来到了桌面进程&#xff0c;这里是真正动画播放的逻辑。 之后又通过IRemoteAnimationFinishedCallback跨进程通信回到系统进程&#xff0c;处理动画结束时的逻辑。 进入…