《代码随想录》--二叉树(一)

news2024/11/24 4:42:23

《代码随想录》--二叉树 第一部分

  • 1、二叉树的递归遍历
  • 2、二叉树的迭代遍历
  • 3、统一风格的迭代遍历代码
  • 4、二叉树的层序遍历
  • 226.翻转二叉树

1、二叉树的递归遍历

前序遍历

中序遍历

后序遍历

代码

  • 前序遍历
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        preOrder(root,list);
        return list;
    }
    public void preOrder(TreeNode root,List<Integer> list){
        if(root == null) return;
        list.add(root.val);
        preOrder(root.left,list);
        preOrder(root.right,list);
    }
}
  • 中序遍历
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        inOrder(root,list);
        return list;
    }
    public void inOrder(TreeNode root,List<Integer> list){
        if(root == null) return;
        inOrder(root.left,list);
        list.add(root.val);
        inOrder(root.right,list);
    }
}
  • 后序遍历
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        postOrder(root,list);
        return list;
    }
    public void postOrder(TreeNode root,List<Integer> list){
        if(root == null) return;
        postOrder(root.left,list);
        postOrder(root.right,list);
        list.add(root.val);
    }
}

2、二叉树的迭代遍历

前序遍历

中序遍历

后序遍历

代码

  • 前序遍历
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if(root == null) return result;
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode node = stack.pop();
            result.add(node.val);
            if(node.right != null) stack.push(node.right);
            if(node.left != null) stack.push(node.left);
        }
        return result;
    }
}
  • 中序遍历
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        while(cur != null || !stack.isEmpty()){
            if(cur != null){
                stack.push(cur);
                cur = cur.left;
            }else{
                TreeNode node = stack.pop();
                list.add(node.val);
                cur = node.right;
            }
        }
        return list;
    }
}
  • 后序遍历
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if(root == null) return list;
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode node = stack.pop();
            list.add(node.val);
            if(node.left != null) stack.push(node.left);
            if(node.right != null) stack.push(node.right);
        }
        Collections.reverse(list);
        return list;
    }
}

分析

  • 非递归的遍历都需要借助来编写代码
  • 前序遍历:
    • 前序遍历是中左右的顺序
    • 先把中间节点放入栈中
    • 再放入右孩子(为什么?因为栈先入后出)
    • 再放入左孩子
  • 中序遍历:
    • 中序遍历的顺序是左中右,但是我们的处理顺序和访问顺序不一致,所以借助指针
    • 定义一个cur指针帮助我们遍历,栈用来处理节点上的元素
  • 后序遍历:
    • 后序遍历的顺序是左右中,可以根据前序遍历改变得到
    • 将遍历顺序改为中左右,最后得到的结果是中右左
    • 反转数组得到正确结果

3、统一风格的迭代遍历代码

  • 前面的迭代遍历代码风格不统一,不像递归代码一样修改代码的位置就能写出三种遍历方式
  • 这里借助空节点标记法

代码

  • 前序
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        if(root != null) stack.push(root);
        while(!stack.isEmpty()){
            TreeNode node = stack.peek();
            if(node != null){
                node = stack.pop();
                if(node.right != null) stack.push(node.right);
                if(node.left != null) stack.push(node.left);
                stack.push(node);
                stack.push(null);
            }else{
                stack.pop();
                node = stack.pop();
                list.add(node.val);
            }
        }
        return list;
    }
}
  • 中序
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        if(root != null) stack.push(root);
        while(!stack.isEmpty()){
            TreeNode node = stack.peek();
            if(node != null){
                node = stack.pop(); //将该节点弹出
                if(node.right != null) stack.push(node.right); //添加左节点
                stack.push(node); //添加中节点
                stack.push(null); //中间节点访问过,但是还没有处理,加入空节点标记
                if(node.left != null) stack.push(node.left); //添加右节点
            }else{
                stack.pop(); //弹出空节点
                node = stack.pop(); //取出栈中元素
                list.add(node.val);
            }
        }
        return list;
    }
}
  • 后序
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        if(root != null) stack.push(root);
        while(!stack.isEmpty()){
            TreeNode node = stack.peek();
            if(node != null){
                node = stack.pop();
                stack.push(node);
                stack.push(null);
                if(node.right != null) stack.push(node.right);
                if(node.left != null) stack.push(node.left);
            }else{
                stack.pop();
                node = stack.pop();
                list.add(node.val);
            }
        }
        return list;
    }
}

分析

  • 可以看到使用空节点标记法,只需要修改两行代码就能写出不同的遍历代码

4、二叉树的层序遍历

学会二叉树的层序遍历,可以一口气打完以下十题:

  • 102.二叉树的层序遍历
  • 107.二叉树的层次遍历II
  • 199.二叉树的右视图
  • 637.二叉树的层平均值
  • 429.N叉树的层序遍历
  • 515.在每个树行中找最大值
  • 116.填充每个节点的下一个右侧节点指针
  • 117.填充每个节点的下一个右侧节点指针II
  • 104.二叉树的最大深度
  • 111.二叉树的最小深度

代码 102题

  • 迭代
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> list = new ArrayList<>();
        if(root == null) return list;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            List<Integer> tempList = new ArrayList<>();
            int len = queue.size();
            while(len > 0){
                TreeNode node = queue.poll();
                tempList.add(node.val);
                if(node.left != null) queue.offer(node.left);
                if(node.right != null) queue.offer(node.right);
                len--;
            }
            list.add(tempList);
        }
        return list;
    }
}
  • 递归
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> list = new ArrayList<>();
        level(root,list,0);
        return list;
    }
    public void level(TreeNode node,List<List<Integer>> list,int depth){
        if(node == null) return;
        depth++;
        if(list.size() < depth){
            List<Integer> tempList = new ArrayList<>();
            list.add(tempList);
        }
        list.get(depth-1).add(node.val);
        level(node.left,list,depth);
        level(node.right,list,depth);
    }
}

分析

  • 迭代法借助了数据结构队列,先入先出。

226.翻转二叉树

leetcode链接
在这里插入图片描述

代码

  • 前序遍历
class Solution {
    public TreeNode invertTree(TreeNode root) {
        preOrderReverse(root);
        return root;
    }
    public void preOrderReverse(TreeNode node){
        if(node == null) return;
        TreeNode temp = node.left;
        node.left = node.right;
        node.right = temp;
        preOrderReverse(node.left);
        preOrderReverse(node.right);
    }
}
  • 后序遍历
class Solution {
    public TreeNode invertTree(TreeNode root) {
        preOrderReverse(root);
        return root;
    }
    public void preOrderReverse(TreeNode node){
        if(node == null) return;
        preOrderReverse(node.left);
        preOrderReverse(node.right);
        TreeNode temp = node.left;
        node.left = node.right;
        node.right = temp;
    }
}
  • BFS
class Solution {
    public TreeNode invertTree(TreeNode root) {
        if(root == null) return root;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(queue.size()>0){
            int size = queue.size();
            for(int i = 0;i < size;i++){
                TreeNode node = queue.poll();
                TreeNode temp = node.left;
                node.left = node.right;
                node.right = temp;
                if(node.left != null) queue.offer(node.left);
                if(node.right != null) queue.offer(node.right);
            }
        }
        return root;
    }
}
  • 统一法
class Solution {
    public TreeNode invertTree(TreeNode root) {
        if(root == null) return root;
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode node = stack.peek();
            if(node != null){
                stack.pop();
                if(node.right != null) stack.push(node.right);
                if(node.left != null) stack.push(node.left);
                stack.push(node);
                stack.push(null);
            }else{
                stack.pop();
                node = stack.pop();
                TreeNode temp = node.left;
                node.left = node.right;
                node.right = temp;
            }
        }
        return root;
    }
}

分析

  • 第一种递归的方式,只能写前序和后序,中序代码会导致有些节点反转了两次
  • 第二种BFS,也就是层序遍历
  • 第三种,统一的写法满足前中后序三种遍历方式

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

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

相关文章

MySQL通过Binlog日志恢复数据库

一、MySQL Binlog 简介 MySQL 的二进制日志 binlog 可以说是 MySQL 最重要的日志&#xff0c;它记录了所有的 DDL 和 DML 语句&#xff08;除了数据查询语句select、show等&#xff09;&#xff0c;以事件形式记录&#xff0c;还包含语句所执行的消耗的时间&#xff0c;MySQL的…

rabbit mq 配置要点

rabbit mq是一款基于AMQP协议&#xff08;Advanced Message Queuing Protocol - 高级消息队列协议&#xff09;的消息队列。 生产者与消费者之间是通过Broker建立连接&#xff0c;在实际的项目中&#xff0c;他们是通过exchange和queue联系在一起的 生产者发送消息流程&#x…

磁盘阵列/视频监控系统EasyCVR新增邮件验证与定时更换登录密码功能

TSINGSEE青犀视频监控汇聚平台EasyCVR可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安防视频监控的能力&…

unity—UGUI 点击按钮后,持续点击空格键会持续出发按钮

在unity开发当中&#xff0c;使用UGUI开发&#xff0c;无论是你代码绑定按钮事件&#xff0c;还是在Inspector窗口直接拖拽绑定的事件&#xff0c;点击按钮事件后&#xff0c;按空格键都会再次执行相关的方法。 默认情况下&#xff0c;Unity将空格键映射为UI按钮的Submit提交操…

【NSX-T】9. 搭建NSX-T环境 —— 使用 OSPF 配置 Tier-0 网关

目录 Lab 说明9.1 创建上行链路网段9.2 创建 Tier-0 网关&#xff08;1&#xff09;设置 Interface 信息&#xff08;2&#xff09;禁用 BGP&#xff08;3&#xff09;启用和配置 OSPF&#xff08;4&#xff09;查看 OSPF Neighbors&#xff08;5&#xff09;为 OSPF 配置路由重…

Vue3配置使用vue-router路由

随着Vue版本的升级&#xff0c;Vue 2.x项目和Vue 3.x项目在使用vue-router上有些区别&#xff0c;本文就简单介绍下vue-router在Vue3中的配置和使用。 一、目录结构 demo/package.jsonvite.config.jsindex.htmlpublic/src/api/assets/common/components/store/views/home.vuel…

二维码智慧门牌管理系统升级解决方案:费用缴纳更便捷

文章目录 前言一、用量查询与数据分析二、一键支付功能三、多种费用管理与多账户使用一、提高生活和工作效率 前言 科技改变生活方式 随着科技的进步&#xff0c;物联网技术正在改变我们的生活方式。在企业和家庭中&#xff0c;费用管理和缴纳是一个重要问题。为了解决这个问题…

《volatile使用与学习总结:2023-12-17》多层面分析学习java关键字--volatile

一、简介 volatile是java中提供的一种轻量级的同步机制&#xff0c;相比于synchronized更加轻量&#xff0c;因为volatile避免了线程频繁的上下文切换和调度&#xff0c;但是也有缺点&#xff0c;同步性差并且使用起来易出错。 二、并发编程的三个概念 原子性 原子性即一个操…

单词搜索 II

题目链接 单词搜索 II 题目描述 注意点 board[i][j] 是一个小写英文字母words[i] 由小写英文字母组成words 中的所有字符串互不相同同一个单元格内的字母在一个单词中不允许被重复使用 解答思路 要想找到一个完整的单词&#xff0c;首先想到的是深度优先遍历&#xff0c;如…

patchless amsi学习(中)

DR7 DR7被称为“调试控制寄存器”&#xff0c;允许对每个硬件断点进行精细控制。其中&#xff0c;前8位控制是否启用了特定的硬件断点。偶数位&#xff08;0、2、4、6&#xff09;称为L0-L3&#xff0c;在本地启用了断点&#xff0c;这意味着仅在当前任务中检测到断点异常时才…

RocketMQ 顺序消息收发实践

目录 概述局部有序创建 Topic配置代码测试 结束 概述 顺序消息 全局有序&#xff1a;适用于性能不是特别高的场景&#xff0c;但是又要求消息又严格一致的概念。局部有序&#xff1a;适用于性能要求高的场景&#xff0c;想办法通过在设计层面处理有序的消息尽量发送至同一个 T…

qt QFile文件操作处理,QFileInfo文件信息读取的简单介绍

QFile类用于文件操作,对文件进行读写操作,可读写文件,二进制文件和qt资源文件.处理文本文件和二进制文件可使用QTextStream类和QDataStream类,处理临时文件可以使用QTemporary,获取文件信息可以使用QFileInfo,处理目录可以使用QDir,监视文件和目录变化可以使用QFileSystemWatch…

整合SSH(Spring+Struts+Hibernate)

0.前言, 由于工作需要故来学习SSH的整合,structs其实相当于(把view和controller结合起来,没有像现在的前后端分离,请求会发送给Action处理,在structs.xml映射地址和类) Hibernate(就是处理数据库的,几乎自动化,也可以写sql语句) Struts&#xff1a;Struts 是一个基于 MVC&#…

【Python】计算一年内的总天数(还有跨年日期)

花了一段时间才找到Python中求一年中总日数&#xff08;total day of the Year&#xff09;的格式代码&#xff0c;所以也把计算方法记录下来。 基本 首先&#xff0c;简单地找出一年中的总天数&#xff0c; strftime() 和 strptime() 的格式代码是 %j ↓看这里 使用 strft…

算法基础之Prim算法求最小生成树

Prim算法求最小生成树 核心思想&#xff1a;Prim 算法 类似于dijkstra算法 更新距离时改为到**集合(生成树)**的距离 最小生成树长这样 每次迭代放一个最近(有边)点&#xff0c;一条最短边进生成树 #include <cstring>#include <iostream>#include <algori…

08-Event Sources和Sink架构

1 PingSource -> Kubernetes Service Sink 架构模型 示例1 部署一个kubernetes类型的sink&#xff0c;这里面还是以event-display为例&#xff0c;下面是资源清单 --- apiVersion: apps/v1 kind: Deployment metadata:name: event-display spec:replicas: 1selector:matc…

Axie Infinity 之后,Ronin 的潜力何在?

作者&#xff1a;stellafootprint.network 数据来源&#xff1a;Ronin Dashboard 备受欢迎的 Web3 游戏 Pixels 在 2023 年 10 月下旬从 Polygon 迁移到了专为游戏设计的区块链 Ronin。Pixels 此前作为 Polygon 上活跃用户&#xff08;钱包数量&#xff09;最多的 Web3 游戏&…

【重点】【DFS】【子集】78.子集

题目 法1&#xff1a;DFS 必须掌握的方法&#xff01;&#xff01;&#xff01; 我们也可以用递归来实现子集枚举。 假设我们需要找到一个长度为 nnn 的序列 aaa 的所有子序列&#xff0c;代码框架是这样的&#xff1a; void dfs(int cur, int n, LinkedList<Integer>…

HTML5+CSS3小实例:3D发光切换按钮效果

目录 一、运行效果 图片效果 二、项目概述 三、开发环境 四、实现步骤及代码 1.创建空文件夹 2.完成页面内容 3.完成css样式 五、项目总结 六、源码获取 一、运行效果 图片效果 二、项目概述 该项目是一个基于HTML和CSS的动态小猫动画。通过使用CSS样式和动画效果…

开源支付项目,还有强大的聚合支付项目,值得借鉴学习,收藏备用

开源支付项目,还有强大的聚合支付项目,值得借鉴学习,收藏备用 自学编程之道2023-03-18 14:26 移动支付随处可见,以前都是微信、支付宝分别各一个收款码,二维码多了之后就不好管理了,随着支付方式的增多,现在基本上都用聚合支付,多种支付方式,一码搞定。针对支付及聚…