二叉树专题

news2024/12/28 19:18:53

请添加图片描述

⭐️前言⭐️

本文主要总结一些常见的二叉树题目,希望读者能够通过这篇文章,来对二叉树有一个更深一步的了解。

🍉欢迎点赞 👍 收藏留言评论 📝私信必回哟😁

🍉博主将持续更新学习记录收获,友友们有任何问题可以在评论区留言

🍉博客中涉及源码及博主日常练习代码均已上传GitHub


请添加图片描述

📍内容导读📍

  • 🍅递归实现遍历
  • 🍅非递归实现遍历
  • 🍅层序遍历
  • 🍅祖先节点
  • 🍅序列化和反序列化
  • 🍅求二叉树某个节点的后继节点
  • 🍅折纸问题
  • 🍅判断二叉树是不是完全二叉树
  • 🍅总结

🍅递归实现遍历

1)理解递归序(每个节点到达三次)
2)先序、中序和后序都可以在递归序的基础上加工出来
3)第一次到达一个节点就打印是先序、第二次打印即中序、第三次即后序
在这里插入图片描述

144. 二叉树的前序遍历

class Solution {
    List<Integer> res=new ArrayList<>();
    public List<Integer> preorderTraversal(TreeNode root) {
        if(root==null) {
            return new ArrayList<>();
        }
        res.add(root.val);
        preorderTraversal(root.left);
        preorderTraversal(root.right);
        return res;
    }
}

145. 二叉树的后序遍历

class Solution {
    List<Integer> res=new ArrayList<>();
    public List<Integer> postorderTraversal(TreeNode root) {
        if(root==null) {
            return new ArrayList<>();
        }
        postorderTraversal(root.left);
        postorderTraversal(root.right);
        res.add(root.val);
        return res;
    }
}

94. 二叉树的中序遍历

class Solution {
    List<Integer> res=new ArrayList<>();
    public List<Integer> inorderTraversal(TreeNode root) {
        if(root==null) {
            return new ArrayList<>();
        }
        inorderTraversal(root.left);
        res.add(root.val);
        inorderTraversal(root.right);
        return res;
    }
}

🍅非递归实现遍历

借助栈,来通过系统栈改为stack栈,将递归改为非递归。

前序:
先入栈的后出栈,所以先入右子树,再入左子树,那么弹出顺序就是先左子树,再右子树,就符合前序根左右的顺序。

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res=new ArrayList<>();
        if(root==null) {
            return res;
        }
        Stack<TreeNode> stack=new Stack<>();
        stack.push(root);
        while(!stack.isEmpty()) {
            TreeNode cur=stack.pop();
            res.add(cur.val);
            if(cur.right!=null) stack.push(cur.right);
            if(cur.left!=null) stack.push(cur.left);
        }
        return res;
    }
}

中序:
递归左子树到最底层,再依次往上回溯记录。

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res=new ArrayList<>();
        if(root==null) return res;
        Stack<TreeNode> stack=new Stack<>();
        TreeNode cur=root;
        while(cur!=null||!stack.isEmpty()) {
            if(cur!=null) {
                stack.push(cur);
                cur=cur.left;
            }else {
                cur=stack.pop();
                res.add(cur.val);
                cur=cur.right;
            }
        }
        return res;
    }
}

后序:
前序遍历的调整,加入根节点后,先入左子树,再入右子树,那么弹出顺序就是根右左,将结果逆序即为后序遍历结果。

class Solution {
    List<Integer> res=new ArrayList<>();
    public List<Integer> postorderTraversal(TreeNode root) {
        if(root==null) return new ArrayList<>();
        Stack<TreeNode> stack=new Stack<>();
        stack.push(root);
        while(!stack.isEmpty()) {
            TreeNode cur=stack.pop();
            res.add(cur.val);
            if(cur.left!=null) stack.push(cur.left);
            if(cur.right!=null) stack.push(cur.right);
        }
        Collections.reverse(res);
        return res;
    }
}

🍅层序遍历

https://leetcode.cn/problems/binary-tree-level-order-traversal/description/
二叉树的按层遍历借助队列来实现

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res=new ArrayList<>();
        if(root==null) return res;
        Queue<TreeNode> queue=new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()) {
            int size=queue.size();
            List<Integer> row=new ArrayList<>();
            while(size-->0) {
                TreeNode cur=queue.poll();
                row.add(cur.val);
                if(cur.left!=null) queue.offer(cur.left);
                if(cur.right!=null) queue.offer(cur.right);
            }
            res.add(row);
        }
        return res;
    }
}

429. N 叉树的层序遍历

class Solution {
    public List<List<Integer>> levelOrder(Node root) {
        List<List<Integer>> res=new ArrayList<>();
        if(root==null) return res;
        Queue<Node> queue=new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()) {
            int size=queue.size();
            List<Integer> row=new ArrayList<>();
            while(size-->0) {
                Node cur=queue.poll();
                row.add(cur.val);
                List<Node> children=cur.children;
                for(Node child:children) {
                    if(child!=null) queue.offer(child);
                }
            }
            res.add(row);
        }
        return res;
    }
}

🍅祖先节点

二叉树节点x的所有祖先节点
在这里插入图片描述

证明:
1、证明祖先节点前序X左,后序X右:
因为先序遍历是先遍历根节点,再去遍历左右子树,所以所有的祖先节点一定出现在节点X以左;同理,后序遍历最后遍历的根节点,所以所有的祖先节点一定出现在X以右。
2、证明交集即为祖先节点:
针对节点X,二叉树上的所有节点可以分为四类,祖先节点、左兄节点、右兄节点和孩子节点。
在这里插入图片描述

在先序遍历中,X节点的左边部分不可能包含孩子节点和右兄节点;
在后序遍历中,X节点的右边部分不可能包含左兄节点;
所以两者的交集即为仅祖先节点。

🍅序列化和反序列化

297. 二叉树的序列化与反序列化

序列化不过就是把结构化的数据打平,本质是在考察二叉树的遍历方式。

public class Codec {
    String SEP=",";
    String NULL="#";
    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        StringBuffer sb=new StringBuffer();
        serialize(root,sb);
        return sb.toString();
    }
    void serialize(TreeNode root,StringBuffer sb) {
        if(root==null) {
            sb.append(NULL).append(SEP);
            return;
        }
        sb.append(root.val).append(SEP);
        serialize(root.left,sb);
        serialize(root.right,sb);
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        LinkedList<String> nodes=new LinkedList<>();
        for(String s:data.split(SEP)) {
            nodes.addLast(s);
        }
        return deserialize(nodes);
    }
    TreeNode deserialize(LinkedList<String> nodes) {
        if(nodes.isEmpty()) return null;
        String first=nodes.removeFirst();
        if(first.equals(NULL)) return null;
        TreeNode root=new TreeNode(Integer.parseInt(first));
        root.left=deserialize(nodes);
        root.right=deserialize(nodes);
        return root;
    }
}

🍅求二叉树某个节点的后继节点

题目:
二叉树结构如下定义:
Class Node {
V value;
Node left;
Node right;
Node parent;
}
给你二叉树中的某个节点,返回该节点的后继节点

题解思路:
后继节点的定义为:中序遍历结果中,该节点紧挨的后一个节点即为其后继节点。
因为节点的定义中有parent指针,所以可以通过先得到中序遍历结果,再去寻找某节点的后继节点,但是这种方式时间复杂度太高。
可以根据中序遍历的特性,直接去找到其后继节点。
如果该节点有右子树,那么其右子树的最左节点即为其后继节点;否则,其后继节点,是该节点为左树的最左节点的根节点。

代码实现:

public class NextNode {
    public static class Node {
        public int value;
        public Node left;
        public Node right;
        public Node parent;

        public Node(int value) {
            this.value = value;
        }
    }
    public static Node getNextNode(Node node) {
        if(node==null) {
            return node;
        }
        if(node.right!=null) return getLeftMost(node.right);
        else {  // 无右子树
            Node parent=node.parent;
            while (parent!=null&&parent.right==node) {  // 当前节点是其父亲节点的右孩子
                node=parent;
                parent=node.parent;
            }
            // 如果因为parent为null而跳出,说明没有后继节点,该节点即为最右节点。
            return parent;
        }
    }

    public static Node getLeftMost(Node node) {
        if(node==null) {
            return node;
        }
        while (node.left!=null) {
            node=node.left;
        }
        return node;
    }
}

🍅折纸问题

题目:
请把一段纸条竖着放在桌子上,然后从纸条的下边向上方对折1次,压出折痕后展开
此时折痕是凹下去的,即折痕突起的方向指向纸条的背面
如果从纸条的下边向上方连续对折2次,压出折痕后展开
此时有三条折痕,从上到下依次是下折痕、下折痕和上折痕。
给定一个输入参数N,代表纸条都从下边向上方连续对折N次
请从上到下打印所有折痕的方向。
N=1时,打印: down
N=2时,打印: down down up

题解思路:
该题目可以先通过折纸来去发现规律,其实折痕的信息就是一棵二叉树的中序遍历结果,该二叉树的特点如下:
1、根节点为down
2、所有左子树的根节点为down
3、所有右子树的根节点为up
遍历该二叉树,并记录其中序遍历结果即为所求。
纸条对折三次,折痕信息如下所示
在这里插入图片描述
代码实现:

public class PaperFolding {
    public static void printAllFolds(int N) {
        process(1,N,true);
    }

    public static void process(int i,int N,boolean fold) {
        if(i>N) {
            return;
        }
        process(i+1,N,true);
        System.out.print(fold?"down ":"up ");
        process(i+1,N,false);
    }

    public static void main(String[] args) {
        int N=3;
        printAllFolds(N);
    }
}

🍅判断二叉树是不是完全二叉树

题解思路:
与相同深度的满二叉树的节点编号一一对应的二叉树就是完全二叉树。

判断是否是完全二叉树可以通过以下两个条件来判断:
1、任意节点如果有右子树而没左子树,则不是完全二叉树。
2、如果遇到左右节点不全的节点,则层序遍历的后序节点必须是叶子节点,否则则不是完全二叉树。

代码实现:

public class IsCBT {
    public static class Node {
        public int value;
        public Node left;
        public Node right;

        public Node(int value) {
            this.value = value;
        }
    }

    public static boolean isCBT(Node head) {
        if(head==null) {
            return true; // 如果为空树默认是完全二叉树
        }
        Queue<Node> queue=new LinkedList<>();
        // 是否遇到过左右孩子不全的节点
        boolean leaf=false;
        Node left=null;
        Node right=null;
        queue.offer(head);
        while (!queue.isEmpty()) {
            head=queue.poll();
            left=head.left;
            right=head.right;
            if((leaf&&(left!=null||right!=null))||(left==null&&right!=null)) return false;
            if(left!=null) queue.offer(left);
            if(right!=null) queue.offer(right);
            if(left==null||right==null) leaf=true;
        }
        return true;
    }
}

🍅总结

遇到二叉树的题目的通用思考过程是:是否可以通过遍历一遍二叉树得到答案?如果不能的话,是否可以定义一个递归函数,通过子问题的答案推导出原问题的答案?如果题目需要子树信息,使用后序遍历(即在后序位置上搞事情)


⭐️最后的话⭐️
总结不易,希望uu们不要吝啬你们的👍哟(^U^)ノ~YO!!如有问题,欢迎评论区批评指正😁

请添加图片描述

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

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

相关文章

【移动端网页布局】flex 弹性布局 ⑥ ( 设置侧轴多行子元素排列方式 | align-content 样式说明 | 代码示例 )

文章目录 一、设置侧轴多行子元素排列方式 : align-content 样式说明1、align-content 样式引入2、align-content 样式属性值 二、代码示例1、代码示例 - 侧轴多行元素从上到下排列2、代码示例 - 侧轴多行元素垂直居中3、代码示例 - 侧轴多行元素平分剩余空间4、代码示例 - 侧轴…

1960-2014年各国二氧化碳排放量(人均公吨数)

1960&#xff0d;2014年各国二氧化碳排放量&#xff08;人均公吨数&#xff09;&#xff08;世界发展指标, 2019年12月更新&#xff09; 1、来源&#xff1a;世界发展指标 2、时间&#xff1a;1960&#xff0d;2014年 3、范围&#xff1a;世界各国 4、指标&#xff1a; 二氧…

C++ STL:set和map的结构及接口使用

目录 一. set和map的简介 1.1 set的简介 1.2 map的简介 二. set的主要接口函数及使用方法 2.1 构造及赋值相关接口函数 2.2 通过迭代器遍历set 2.3 结构修改相关接口函数 2.4 其他主要接口函数 三. map的主要接口函数及使用方法 3.1 构造和赋值相关接口函数 3.2 通…

Midjourney放大招,什么好看唯美高清,统统都是我的

你知道吗&#xff1f;超过99%的人都没有足够出色的肖像照来展现自己的魅力&#xff0c;除非你是那种在网上拥有成千上万张自己肖像照的大明星。但是&#xff0c;好消息来了&#xff01;现在有一个InsightFaceSwap Discord bot&#xff0c;可以帮助你实现这个“不可能完成”的想…

【JavaEE初阶】多线程进阶(五)常见锁策略 CAS synchronized优化原理

文章目录 常见锁策略乐观锁 & 悲观锁轻量级锁 & 重量级锁自旋锁 & 挂起等待锁互斥锁 & 读写锁公平锁 & 非公平锁可重入锁 & 不可重入锁synchronized对应以上的锁策略锁策略中的面试题&#xff1a; CASCAS的介绍CAS如何实现CAS的应用场景CAS的典型问题&…

Excel公式:将日期转换为月份年

Excel公式&#xff1a;将日期转换为月份年 在Excel中&#xff0c;您可以将日期单元格格式化为多种类型的日期格式&#xff0c;但是在某些情况下&#xff0c;您希望将日期转换为文本格式&#xff0c;仅转换为月&#xff0c;年&#xff0c;日或月年&#xff0c;日月或年日。 在本…

Java全栈学习路线总结,科班程序员搬砖逆袭

&#x1f307;文章目录 前言一、前置知识二、 Web前端基础示例&#xff1a;1.文本域2.密码字段 三、后端基础一. Java基础二. 数据库技术三. Web开发技术四. 框架技术五. 服务器部署 四、其他技术五、全栈开发六、综合实践七、学习教程一、前端开发二、后端开发三、数据库开发四…

VUE 学习笔记(三) Vue 渲染流程详解

在 Vue 里渲染一块内容&#xff0c;会有以下步骤及流程&#xff1a; 第一步&#xff0c;解析语法&#xff0c;生成AST 第二步&#xff0c;根据AST结果&#xff0c;完成data数据初始化 第三步&#xff0c;根据AST结果和DATA数据绑定情况&#xff0c;生成虚拟DOM 第四步&…

ESP32设备驱动-Si1145红外接近-紫外 (UV) 指数和环境光传感器驱动

Si1145红外接近-紫外 (UV) 指数和环境光传感器驱动 文章目录 Si1145红外接近-紫外 (UV) 指数和环境光传感器驱动1、Si1145介绍2、硬件准备3、软件准备4、驱动实现1、Si1145介绍 Si1145/46/47 是一款低功耗、基于反射的红外接近、紫外 (UV) 指数和环境光传感器,具有 I2C 数字接…

电脑百度网盘打不开怎么办 电脑百度网盘双击没反应处理方法

有时候我们想要在电脑浏览器上下载一些文件时&#xff0c;打开的文件下载链接有些需要通过百度网盘来存储下载&#xff0c;然而当用户在电脑中安装完百度网盘工具之后&#xff0c;双击想要打开时却总是没反应&#xff0c;对此电脑百度网盘打不开怎么办呢&#xff1f;接下来小编…

Java反射和动态代理

反射 反射允许对封装类的成员变量、成员方法和构造方法的信息进行编程访问 成员变量&#xff1a;修饰符、名字、类型、get/set值 构造方法&#xff1a;修饰符、名字、形参、创建对象 成员方法&#xff1a;修饰符、名字、形参、返回值、抛出的异常、获取注解、运行方法 获取…

【云原生进阶之PaaS中间件】第一章Redis-1.1简介

1 Redis概述 1.1 Redis 简介 Redis&#xff08;Remote Dictionary Server )&#xff0c;即远程字典服务&#xff0c;是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库&#xff0c;并提供多种语言的API&#xff0c;可用作数据库&#…

高质量毕业答辩PPT模板+PPT网站

文章目录 前言一、iSlide二、office plus三、优品PPT总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 又是一年毕业季&#xff0c;又到了快要答辩的时候&#xff0c;最近有一些小伙伴找我要毕业答辩PPT模板&#xff0c;本着这不能拒绝啊的心态&…

20230507使用python3批量转换DOCX文档为TXT

20230507使用python3批量转换DOCX文档为TXT 2023/5/7 20:22 WIN10使用python3.11 # – coding: gbk – import os from pdf2docx import Converter from win32com import client as wc """这里需要安转包pywin32com""" # 读取pdf文件文本内容 …

探秘二分查找中的数学奇迹:如何手动求解整数x的平方根

本篇博客会讲解力扣“69. x 的平方根”这道题的解题思路。这是题目链接。 大家先来审下题&#xff1a; 以及示例&#xff1a; 还有提示&#xff1a; 本题常规的思路有&#xff1a;暴力查找、转换成指数和对数、二分查找、牛顿迭代。 转换成指数和对数的方法非常简单&#…

接口自动化测试框架9项必备功能有哪些?你一定不知道

当你准备使用一个接口测试框架或者自造轮子的时候&#xff0c;或许你需要先了解下一个接口自动化测试框架必须具备什么功能。 一、校验   这个很好了解&#xff0c;如果没有校验&#xff0c;单纯的执行接口的话&#xff0c;那就谈不上测试了。所以支持对返回值校验是一个必须…

[Golang] 爬虫实战-获取动态页面数据-获取校招信息

&#x1f61a;一个不甘平凡的普通人&#xff0c;致力于为Golang社区和算法学习做出贡献&#xff0c;期待您的关注和认可&#xff0c;陪您一起学习打卡&#xff01;&#xff01;&#xff01;&#x1f618;&#x1f618;&#x1f618; &#x1f917;专栏&#xff1a;算法学习 &am…

Solr(1):Solr概述

1 概述 Solr 是一个基于 Apache Lucene 之上的搜索服务器&#xff0c;它是一个开源的、基于 Java 的信息检索库。它旨在驱动功能强大的文档检索应用程序 - 无论您需要根据用户的查询将数据服务到何处&#xff0c;Solr 都可以为您服务。Solr与应用程序的集成以为您服务。 下面…

es 7.x 通过DSL语句添加doc数据

一 在es中doc数据的crud操作 1.1 说明 本案例操作 接上一篇的基础上进行操作。 1.2 添加doc 方式为post http://localhost:9200/order_item/_doc 添加文档数据 必须是post提交&#xff0c;不能是put 1.3 查看文档数据 http://localhost:9200/order_item/_doc/_searc…

118-Linux_数据库_索引

文章目录 一.索引是什么?二.索引为什么选择b树三.测试索引1.在mysql中创建数据库 test_indexdb2.在test_indexdb中创建表 test_index3.运行程序向表中插入1万条数据&#xff0c;都是字符串4. 查询验证 一.索引是什么? 索引是一种特殊的文件&#xff0c;它包含着对数据表里所…