二叉树常见题目

news2024/11/24 0:58:11

目录

一、判断一棵树是否为另一棵树的子树

二、判断是否对称二叉树 

三、翻转二叉树 

四、二叉树构建及遍历 

五、根据二叉树创建字符串

六、二叉树的最近公共祖先

七、根据前序遍历和中序遍历构造二叉树

八、根据后序遍历和中序遍历构造二叉树 

九、二叉树前序非递归遍历

十、二叉树中序非递归遍历

十一、二叉树后序非递归遍历


一、判断一棵树是否为另一棵树的子树

在编写该函数之前首先应该再编写一个函数判断两个树是否相同,假设两个树分别为t和st,然后再判断若 t和st相同表示st就是t的子树,因为一棵树本身也是自己的子树,否则就判断st是否为t的左子树或是否为t的右子树。

public boolean isEquals(TreeNode root1,TreeNode root2){
        if(root1==null&&root2==null){
            return true;
        }
        if (root1==null||root2==null){
            return false;
        }
        if(root1.val!=root2.val){
            return false;
        }
        return isEquals(root1.left,root2.left)&&isEquals(root1.right,root2.right);
        
    }
    //判断一棵树是否为另一棵树的子树
public boolean isSubtree(TreeNode root, TreeNode subRoot){
        if(root==null||subRoot==null){
            return false;
        }
       if(isEquals(root,subRoot)) return true;
       return isSubtree(root.left,subRoot) || isSubtree(root.right,subRoot);
    }

二、判断是否对称二叉树 

如上图所示就是二叉树,如果左孩子与右孩子相等,还需要判断左孩子的左孩子的左节点与右孩子的右结点是否相等,然后继续递归判断。

public boolean isSymmetric(TreeNode root) {
       if(root==null){
           return false;
       }
       return isSymmetricChild(root.left,root.right);
    }
public boolean isSymmetricChild(TreeNode lc,TreeNode rc) {
       if(lc==null&&rc==null){
           return true;
       }
       if(lc==null||rc==null){
           return false;
       }
       if(lc.val!=rc.val){
           return false;
       }
       return isSymmetricChild(lc.left,rc.right) && isSymmetricChild(lc.right,rc.left);
    }

三、翻转二叉树 

若二叉树不为空,就将二叉树的左右结点进行交换,接着递归交换左子树,最后递归交换右子树。

public TreeNode invertTree(TreeNode root) {
        if(root==null){
            return null;
        }
        TreeNode temp=root.left;
        root.left=root.right;
        root.right=temp;
        invertTree(root.left);
        invertTree(root.right);
        return root;
    }

四、二叉树构建及遍历 

题目描述:编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。

解题思路:对字符串进行遍历,若遍历得到的字符不为‘#’则表示非空,就将该字符包装为二叉树的根结点,然后继续递归遍历分别用该根结点的左右孩子结点接收。                              

static class TreeNode{
        char val;
        TreeNode left;
        TreeNode right;
        public TreeNode(char val){
            this.val=val;
        }
    }
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNextLine()) { // 注意 while 处理多个 case
            String str=in.nextLine();
            TreeNode root=createTree(str);
            inOrder(root);
        }
    }
    public static int i = 0;
    public static TreeNode createTree(String str) {
        TreeNode root = null;
        if(str.charAt(i) != '#') {
            root = new TreeNode(str.charAt(i));
            i++;
            root.left = createTree(str);
            root.right = createTree(str);
        }else {
            i++;
        }
        return root;
    }
    public static void inOrder(TreeNode root){
        if(root==null){
            return;
        }
        inOrder(root.left);
        System.out.print(root.val+" ");
        inOrder(root.right);
    }

五、根据二叉树创建字符串

题目描述:给你二叉树的根节点 root ,请你采用前序遍历的方式,将二叉树转化为一个由括号和整数组成的字符串,返回构造出的字符串。空节点使用一对空括号对 "()" 表示,转化后需要省略所有不影响字符串与原始二叉树之间的一对一映射关系的空括号对。

 解题思路:由示例1和示例2可以推出当一个结点的左孩子为空右孩子不为空时就需要添加“()”,如果左孩子不为空,右孩子为空时直接忽略,左右孩子都为空也是直接忽略。

对树进行遍历,若左子树不为空则需要添加“(”,对左子树进行递归遍历,结束后加上“)”,若左子树为空,右子树不为空就要添加“()”,否则直接返回,接着继续对右子树遍历,若右子树不为空,则添加“(”,对右子树进行递归遍历,结束后加上“)”。

public String tree2str(TreeNode root) {
        if(root==null){
            return null;
        }
        StringBuilder stringBuilder=new StringBuilder();
        treeStr(root,stringBuilder);
        return stringBuilder.toString();

    }
    public void treeStr(TreeNode root,StringBuilder stringBuilder){
        if(root == null){
            return;
        }
        stringBuilder.append(root.val);
        if(root.left!=null){
            stringBuilder.append("(");
            treeStr(root.left,stringBuilder);
            stringBuilder.append(")");
        }else{
            if(root.right!=null){
                stringBuilder.append("()");
            }else{
                return;
            } }
        if(root.right!=null){
            stringBuilder.append("(");
            treeStr(root.right,stringBuilder);
            stringBuilder.append(")");
        }else {
            return;
        }
    }

六、二叉树的最近公共祖先

最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先),已知p、q全都存在于这棵二叉树。

解题思路一:

使用递归的思想,在树不为空的情况下,若根结点为p或q就直接返回根结点,然后递归遍历左子树和右子树分别用node1和node2接收,如果node1和node2都不为空,则表示这两个结点分别在根结点的两侧,那么就返回根结点,若有node1不为空或node2不为空就返回node1和node2,若都为空则就返回null。

public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root==null){
            return null;
        }
        if(p==root||q==root){
            return root;
        }
        TreeNode node1=lowestCommonAncestor(root.left,p,q);
        TreeNode node2=lowestCommonAncestor(root.right,p,q);
       if(node1 != null && node2 != null){
           return root;
       }else if(node1 != null){
           return node1;
       }else if(node2 != null){
           return node2;
       }else{
           return null;
       }
    }

解题思路二:

可以通过求两个结点从根结点到其的路径,然后通过遍历路径来求最近公共祖先,那么如何求路径?

求路径使用栈结构利用其先进后出的思想,如果所遍历的结点不是路径就可以将其弹出,首先如果根结点和要求路径的结点都不为空,首先将根结点入栈,如果根结点就是要求路径的结点就直接返回true,否则就求路径递归左子树,如果递归结果为真则表示已经找到就返回true,否则就求路径递归右子树,如果递归结果为真也返回true,否则就表示左右子树都未找到就需要弹出结点,然后返回false。

在求最近公共祖先的方法中分别对p和q调用求路径的方法,然后将路径存放到各自的栈,对两个栈进行遍历,查看是否有最近公共祖先。 

public TreeNode lowestCommonAncestor2(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null || p == null || q == null){
            return null;
        }
        Deque<TreeNode> stack1=new LinkedList<>();
        Deque<TreeNode> stack2=new LinkedList<>();
        getPath(root,p,stack1);
        getPath(root,q,stack2);
        int size =stack1.size()-stack2.size();
        if(size>0){
            while(size != 0){
                stack1.pop();
                size--;
            }
        }else{
            size=stack2.size()-stack1.size();
            while(size != 0){
                stack2.pop();
                size--;
            }
        }
        while(!stack1.isEmpty() && !stack2.isEmpty()){
            TreeNode node1 = stack1.pop();
            TreeNode node2 = stack2.pop();
            if(node1 == node2){
                return node1;
            }
        }
        return null;
    }
   public boolean getPath(TreeNode root, TreeNode node, Deque<TreeNode> stack){
        if(root == null || node == null){
            return false;
        }
        stack.push(root);
        if(root == node){
            return true;
        }
        boolean flag1 = getPath(root.left,node,stack);
        if(flag1){
            return true;
        }
       boolean flag2 = getPath(root.right,node,stack);
       if(flag2){
           return true;
       }
       stack.pop();
       return false;
    }

七、根据前序遍历和中序遍历构造二叉树

前序遍历的顺序是根-左-右,中序遍历的顺序是左-根-右,就可以创建一个递归函数,参数为前序遍历数组和中序遍历的数组以及开始点ib和结束点ie,当ib>ie是就退出递归,此时已经越界,否则就将i所指的元素包装为根结点,可以定义一个变量i从0开始对前序遍历的序列进行遍历,得到i对应的元素k,k就为根结点,然后在中序遍历中查找k对应的下标index,那么左子树的范围就是0~index-1,右子树的范围是index+1~len,len表示数组长度,然后逐步递归,最后返回root。

public static int i=0;
    public static TreeNode buildTree(int[] preorder, int[] inorder) {
        return buildTreeChild(preorder,inorder,0,inorder.length-1);
    }
    public static TreeNode buildTreeChild(int[] preorder, int[] inorder,int ib,int ie) {
        if(ib>ie){
            return null;
        }
        TreeNode root=new TreeNode(preorder[i]);

        int index=find(inorder,root.val,ib,ie);

        i++;
        root.left=buildTreeChild(preorder,inorder,ib,index-1);

        root.right=buildTreeChild(preorder,inorder,index+1,ie);
        return root;

    }
    public static int find(int[] arr,int num,int begin,int end){
        for (int i=begin;i<=end;i++){
            if(arr[i] == num){
                return i;
            }
        }
        return -1;
    }

八、根据后序遍历和中序遍历构造二叉树 

与上题类似,但是后序遍历的顺序是左-右-根,后序遍历的最后一个元素为根节点,那么定义的i变量就从后往前进行遍历,同时需要先创建右子树再创建左子树。

public  static int k=0;
public static TreeNode buildTree2(int[] inorder, int[] postorder) {
        k=postorder.length-1;
        return buildTreeChild2(postorder,inorder,0,inorder.length-1);
    }
public static TreeNode buildTreeChild2(int[] postorder, int[] inorder,int ib,int ie) {
        if(ib>ie){
            return null;
        }
        TreeNode root=new TreeNode(postorder[i]);
        int index=find(inorder,root.val,ib,ie);
        k--;
        root.right=buildTreeChild2(postorder,inorder,index+1,ie);
        root.left=buildTreeChild2(postorder,inorder,ib,index-1);

        return root;
    }
public static int find(int[] arr,int num,int begin,int end){
        for (int i=begin;i<=end;i++){
            if(arr[i] == num){
                return i;
            }
        }
        return -1;
    }

九、二叉树前序非递归遍历

前序遍历的顺序是根-左-右,遍历结果使用list接收,那么就可以使用栈,在树非空的情况下,就定义一个结点cur指向根结点,然后一直向下指向该结点的左子树并将cur添加到list中,list每次接收的都是子树的根结点如果cur为空了,就弹出栈顶元素top,此时栈顶元素刚好存放的是cur的根结点,就让cur指向top,如果此时栈也不为空并且cur也不为空,就继续循环。

public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new LinkedList<>();
        if(root == null){
            return list;
        }
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur=root;
        while(cur != null || !stack.isEmpty()){
            while(cur != null){
                list.add(cur.val);
                stack.push(cur);
                cur=cur.left;
            }
            TreeNode top=stack.pop();
            if(top!=null){
                cur=top.right;
            }
        }
       return list;
    }

十、二叉树中序非递归遍历

中序遍历的顺序是左-根-右,与上述前序遍历的思路基本一致,只不过在list添加的是每次出栈的元素,此是就符合中序遍历的顺序。

public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list=new LinkedList<>();
        Stack<TreeNode> stack=new Stack<>();
        TreeNode cur=root;
        while(cur!=null||!stack.isEmpty()){
            while(cur!=null){
                stack.push(cur);
                cur=cur.left;
            }
            TreeNode top=stack.pop();
            list.add(top.val);
            cur=top.right;
        }
        return list;

    }

十一、二叉树后序非递归遍历

后序遍历的顺序是左-右-根,那么同样使用栈,定义一个结点cur指向root,一直遍历左子树,若为空则取栈顶元素top,若不为空cur就指向top的右子树进行遍历,否则就弹出元素,并加入到遍历集合list中,但是这样的话就会陷入循环会继续遍历右子树,于是增加一个perv记录每次弹出的元素,若top的右子树为空或top的右子树与prev相等就继续弹出元素进行遍历。

public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list=new LinkedList<>();
        Stack<TreeNode> stack=new Stack<>();
        TreeNode cur=root;
        TreeNode prev = null;
        while(cur!=null||!stack.isEmpty()){
            while(cur!=null){
                stack.push(cur);
                cur=cur.left;
            }
            TreeNode top=stack.peek();
            if(top.right==null||prev==top.right ){
                TreeNode node = stack.pop();
                prev=node;
                list.add(node.val);
            }else{
                cur=top.right;
            }
        }
        return list;

    }

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

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

相关文章

MySQL——“order by”是如何工作的

假设目前有这么一个表 CREATE TABLE t (id int(11) NOT NULL,city varchar(16) NOT NULL,name varchar(16) NOT NULL,age int(11) NOT NULL,addr varchar(128) DEFAULT NULL,PRIMARY KEY (id),KEY city (city) ) ENGINEInnoDB; 业务要求是要查询城市是“杭州”的所有人名字&a…

1.2计算机系统的层次结构

文章目录&#xff08;1&#xff09;微指令&#xff08;2&#xff09;汇编语言&#xff08;3&#xff09;高级语言&#xff08;4&#xff09;操作系统&#xff08;5&#xff09;编译程序与解释程序&#xff08;6&#xff09;总结请先食用这一篇 计算机工作过程&#xff08;1&…

考研《数据结构》线性表—顺序表练习题

2.设计一个高效算法&#xff0c;将顺序表L的所有元素逆置&#xff0c;要求算法的空间复杂度为0&#xff08;1&#xff09;。 思路&#xff1a;扫描顺序表L的前半部分元素&#xff0c;对于元素L.data[i]与L.data[len-1-i]对换。 #include<iostream> using namespace std…

XCTF:NewsCenter

一道简单的常规注入题&#xff0c;就当练练手了 尝试’ 直接网页异常&#xff0c;尝试进行闭合# 网页恢复正常&#xff0c;证明SQL语句通过单引号进行闭合&#xff0c;则为字符型注入 直接判断字段数&#xff0c;order by n order by 3#回显正常&#xff0c;order by 4#网页异…

kaggle平台学习复习笔记 | 数据划分与模型集成

目录数据集划分与交叉验证模型集成方法Titanic为例的简单应用kaggle比赛相关tips数据集划分与交叉验证 数据集划分 通常有两种方法&#xff1a; 留出法(Hold-out) 适用于数据量大的情况K折交叉验证(K-fold CV) 适用于数据量一般情况 时间比较长自助采样(Bootstrap) 较少使用 …

Lua C接口编程(二)

引言 上篇文章我们学习了C如何调用Lua&#xff0c;今天我们就来聊聊Lua 如何调用C。 Lua版本&#xff1a;Lua 5.3.5 对于Lua提供的接口有不清楚的&#xff0c;可以参考Lua接口官方文档 一、Lua调用C步骤 需要将C文件编译成动态库在Lua文件中使用package.cpath配置C动态库路…

Linux学习笔记——分布式内存计算Spark安装部署

5.12、分布式内存计算Spark环境部署 5.12.1、简介 Spark是一款分布式内存计算引擎&#xff0c;可以支撑海量数据的分布式计算。 Spark在大数据体系是明星产品&#xff0c;作为最新一代的总和计算引擎&#xff0c;支持离线计算和实时计算。 在大数据领域广泛应用&#xff0c…

虚拟化技术考试重点总结

虚拟化技术考试重点总结 什么是虚拟化&#xff1f;其作用是什么 ​ 虚拟化&#xff0c;是指通过虚拟化技术将一台计算机虚拟为多台逻辑计算机。可以在一台计算机上同时运行多个逻辑计算机&#xff0c;每个逻辑计算机可运行不同的操作系统&#xff0c;并且应用程序都可以在相互…

Golang中http编程

http介绍 编写web语言&#xff1a; 1.java 2.php&#xff0c;现在都在尝试用go语言编写 3.python&#xff0c;豆瓣 4.go语言 》 beego&#xff0c;gin两个主流的web框架 https协议&#xff1a;我们使用浏览器访问的时候发送的就是http请求 http是应用层的协议&#xff0c;底…

论文投稿指南——中文核心期刊推荐(地质学)

【前言】 &#x1f680; 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊 &#x1f384; 在期刊论文的分布中&#xff0c;存在一种普遍现象&#xff1a;即对于某一特定的学科或专业来说&#xff0c;少数期刊所含…

广告业务系统 之 辅助决策 —— “ AB 实验平台”

文章目录广告业务系统 之 辅助决策 —— “ AB 实验平台”AB 实验平台流量侧 & 渲染侧AB 实验模块架构设计智能流控广告业务系统 之 辅助决策 —— “ AB 实验平台” AB 实验平台 在广告业务中&#xff0c;数据通常作为业务前进的内在驱动力之一。 AB 实验平台就是以实验…

java获取时间并进行计算

前言 SimpleDateFormat使用介绍 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、SimpleDateFormat是什么&#xff1f; 如果你对java源码比较了解。你会发现java对文字&#xff0c;数字的格式化&#xff0c;是有一个公共的父类的Format。 NumberFo…

.Net Core6.0程序发布到IIS支持apk文件下载

ASP.Net Core6.0 WebApi程序发布到IIS支持apk/wgt文件下载 IIS中配置MIME 添加.apk/.wgtapplication/vnd.android.package-archive或application/octet-stream.Net Core6.0 WebApi 程序要在startup.cs中设置 //使用默认文件 app.UseDefaultFiles(); //开启静态文件 app.UseS…

金山区企业工程技术研究中心给予15万元资金奖励

金山区企业工程技术研究中心一、主管部门金山区科学技术委员会二、政策依据《金山区关于进一步鼓励科技创新加快上海科技创新中心重要承载区建设的若干配套政策》&#xff08;金府发〔2020〕3号&#xff09;《金山区关于进一步鼓励科技创新加快上海科技创新中心重要承载区建设的…

赛题发布|“星河杯”隐私计算大赛-赛题发布沙龙成功举办

2023年1月10日下午&#xff0c;由中国信通院与隐私计算联盟主办&#xff0c;中移动信息技术有限公司、联通数字科技有限公司、天翼电子商务有限公司共同协办&#xff0c;FATE开源社区提供技术支持&#xff0c;DataFountain作为官方竞赛平台的“星河杯”隐私计算大赛顺利举办赛题…

Acwing---1212.地宫取宝

地宫取宝1.题目2.基本思想3.代码实现1.题目 X 国王有一个地宫宝库&#xff0c;是 nm 个格子的矩阵&#xff0c;每个格子放一件宝贝&#xff0c;每个宝贝贴着价值标签。 地宫的入口在左上角&#xff0c;出口在右下角。 小明被带到地宫的入口&#xff0c;国王要求他只能向右或…

SAP入门技术分享三:模块化程序

模块化程序1.子程序概要2.子程序定义3.子程序参数&#xff08;1&#xff09;传递参数的方法&#xff08;2&#xff09;定义参数类型&#xff08;3&#xff09;参数与结构体&#xff08;4&#xff09;参数与内表4.调用子程序&#xff08;1&#xff09;调用程序内部子程序&#x…

Android APP 缓存路径

Context.getCacheDir():这个缓存路径打印出来的是&#xff1a;data / data / (APPID ) / cacheAndroid系统中的清除APP缓存清除的就是这个路径: 随着用户手动清空缓存或者APP的卸载&#xff0c;这个路径的缓存也会被删除。请注意&#xff1a;在这个缓存路径上读写是不需要请求文…

Qt扫盲-信号槽理论总结

信号槽理论总结一、概述二、信号槽三、信号四、槽函数五、小例子六、 信号槽的默认参数七、高级使用八、 在Qt 里使用第三方的信号槽一、概述 信号和槽用于对象之间的通信。信号和槽机制是Qt的一个核心特性&#xff0c;也是与其他框架所提供的特性最大不同的部分。Qt的元对象系…

win10跨网段文件共享

win10跨网段文件共享问题描述问题分析网络可达性防火墙权限问题操作网络拓扑示意图操作步骤问题描述 平常&#xff0c;我们经常用的是同一局域网下的网络共享&#xff0c;这在windows上很容易操作。现在&#xff0c;两台PC主机不在同一子网&#xff0c;该如何共享&#xff1f;…