【刷题笔记】二叉树3

news2024/11/15 13:51:14

        之前已经介绍过了二叉树的前中后序遍历及层序遍历,这是解决所有二叉树问题的手段。上一期也提到过,很多题既可以用前中后序遍历去做也可以用层序遍历去做。本期就介绍一下例题,分别展示两种做法。

1. 二叉树的右视图

199. 二叉树的右视图

        给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

1.1 方法1:前序遍历

        因为右视图的节点可能分布在各个位置,即处于某一层最右侧的节点有可能在左子树,也有可能在右子树,有可能在左子树的左子树,也有可能在右子树的左子树......因此,采用前序遍历的方式也需要遍历整棵树,时间复杂度为O(n)。

        所以,前序遍历的想法就是,用一个高度值curHeight记录你当前所在层的高度,用一个List去收集每一层的最右侧的值。遍历的时候先把List填满,后序如果有更深的深度再往List中放值。后面遍历的时候再在相同高度发现List中有值,说明List中存的已经不是最右侧的了,就更新这个值。

        图解如下:

    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if (root == null) {
            return res;
        }
        dfs(res, root, 0);
        return res;
    }

    private void dfs(List<Integer> res, TreeNode root, int curHeight) {
        if (res.size() == curHeight) {
            res.add(root.val);
        } else {
            res.set(curHeight, root.val);
        }
        if (root.left != null) {
            dfs(res, root.left, curHeight + 1);
        }
        if (root.right != null) {
            dfs(res, root.right, curHeight + 1);
        }
    }

1.2 方法2:层序遍历

          层序遍历与上一期代码类似,自行理解。

    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if (root == null) {
            return res;
        }
        Deque<TreeNode> deque = new LinkedList<>();
        deque.push(root);
        while (!deque.isEmpty()) {
            int size = deque.size();
            while (size-- > 0) {
                TreeNode pop = deque.pop();
                if(size == 0) {
                    res.add(pop.val);
                }
                if (pop.left != null) {
                    deque.addLast(pop.left);
                }
                if (pop.right != null) {
                    deque.addLast(pop.right);
                }
            }
        }
        return res;
    }

2. 二叉树的层平均值

637. 二叉树的层平均值

        给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受

2.1 方法1:前序遍历

        解法思路同右视图,即在遍历二叉树的每一条路径的时候用一个List记录对应位置的值,只不过右视图是每当发现新值就更新,本题是每当在对应深度发现新值就在List对应位置给做加和,同时再用一个List在对应深度记录当前深度的节点数。最后获取两个List,每个相同位置元素做除法,就得到了层平均值。

    public List<Double> averageOfLevels(TreeNode root) {
        List<Double> sums = new ArrayList<>();
        if (root == null) {
            return sums;
        }
        List<Integer> nums = new ArrayList<>();
        dfs(sums, root, nums, 0);
        List<Double> res = new ArrayList<>();
        for (int i = 0; i < nums.size(); i++) {
            res.add(i, sums.get(i) / nums.get(i));
        }
        return res;
    }

    private void dfs(List<Double> sums, TreeNode root, List<Integer> nums, int curHeight) {
        if (sums.size() == curHeight) {
            sums.add(root.val * 1.0);
            nums.add(1);
        } else {
            sums.set(curHeight, sums.get(curHeight) + root.val);
            nums.set(curHeight, nums.get(curHeight) + 1);
        }
        if (root.left != null) {
            dfs(sums, root.left, nums, curHeight + 1);
        }
        if (root.right != null) {
            dfs(sums, root.right, nums, curHeight + 1);
        }
    }

2.2 方法2:层序遍历

    public List<Double> averageOfLevels(TreeNode root) {
        List<Double> res = new ArrayList<>();
        Deque<TreeNode> deque = new LinkedList();
        deque.push(root);
        while (!deque.isEmpty()) {
            int size = deque.size();
            Double sum = 0d;
            int nums = size;
            while (size-- > 0) {
                TreeNode pop = deque.pop();
                sum += pop.val;
                if (pop.left != null) {
                    deque.addLast(pop.left);
                }
                if (pop.right != null) {
                    deque.addLast(pop.right);
                }
            }
            res.add(sum / nums);
        }
        return res;
    }

3. 二叉树层最大值

515. 在每个树行中找最大值

        给定一棵二叉树的根节点 root ,请找出该二叉树中每一层的最大值。

3.1 方法一:前序遍历

        还是熟悉的配方用一个curHeight记录当前高度,然后在遍历的时候一旦到了相同的高度,就对比List中存的值和现在的值哪个,如果比存的值大,就更新List对应位置的值。

    public List<Integer> largestValues(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if (root == null) {
            return res;
        }
        dfs(res, root, 0);
        return res;
    }

    private void dfs(List<Integer> res, TreeNode root, int curHeight) {
        if (res.size() == curHeight) {
            res.add(root.val);
        } else {
            res.set(curHeight, Math.max(res.get(curHeight), root.val));
        }
        if (root.left != null) {
            dfs(res, root.left, curHeight + 1);
        }
        if (root.right != null) {
            dfs(res, root.right, curHeight + 1);
        }
    }

3.2 方法二:层序遍历

    public List<Integer> largestValues(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if (root == null) {
            return res;
        }
        Deque<TreeNode> deque = new LinkedList<>();
        deque.push(root);
        while (!deque.isEmpty()) {
            int size = deque.size();
            int maxValue = deque.peek().val;
            while (size-- > 0) {
                TreeNode pop = deque.pop();
                maxValue = Math.max(maxValue, pop.val);
                if (pop.left != null) {
                    deque.addLast(pop.left);
                }
                if (pop.right != null) {
                    deque.addLast(pop.right);
                }
            }
            res.add(maxValue);
        }
        return res;
    }

4. 填充每个节点的下一个右侧节点指针

116. 填充每个节点的下一个右侧节点指针

        给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:

struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}

        填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。初始状态下,所有 next 指针都被设置为 NULL

117. 填充每个节点的下一个右侧节点指针 II

        给定一个二叉树:

struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}

        填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL 。初始状态下,所有 next 指针都被设置为 NULL 。

        两道题解法几乎一样,在这里给出通用的代码(一套代码打两个)。

4.1 方法一:前序遍历

        思路与之前相似,记录高度,每次遍历到曾经遍历过的高度,就让List中存的next指向当前节点,并把当前节点更新到List中以便下一次的引用指向。

    public static Node connect(Node root) {
        if (root == null) {
            return root;
        }
        Node cur = root;
        List<Node> records = new ArrayList<>();
        dfs(records, cur, 0);
        return root;
    }

    private static void dfs(List<Node> records, Node root, int curHeight) {
        if(root == null) {
            return;
        }
        if (records.size() == curHeight) {
            records.add(root);
        } else {
            Node node = records.get(curHeight);
            node.next = root;
            records.set(curHeight, root);
        }
        dfs(records, root.left, curHeight + 1);
        dfs(records, root.right, curHeight + 1);
    }

4.2 方法二:层序遍历

    public Node connect(Node root) {
        Deque<Node> deque = new LinkedList<>();
        if (root != null) {
            deque.push(root);
        }
        while (!deque.isEmpty()) {
            int size = deque.size();
            while (size-- > 0) {
                Node node = deque.pollFirst();
                if (size != 0) {
                    node.next = deque.peek();
                } else {
                    node.next = null;
                }
                if (node.left != null) {
                    deque.addLast(node.left);
                }
                if (node.right != null) {
                    deque.addLast(node.right);
                }
            }
        }
        return root;
    }

        这个层序遍历,由于116题中,说了是完美二叉树,所以做116的时候可以不用写两个判断,写一个也是可以的。上面代码是一个通用的解法,怎么写都可以。

                if (pop1.left != null) {
                    deque.addLast(pop1.right);
                    deque.addLast(pop1.left);
                }

5. 二叉树的最大深度

104. 二叉树的最大深度

        给定一个二叉树 root ,返回其最大深度。二叉树的最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。

5.1 方法一:后序遍历

        这道题用递归是最简单的,为什么用后序遍历呢?在这里说一下思路,最好的解决办法就是:

        (1)求取当前节点左子树的深度;

        (2)再求取当前节点右子树的深度;

        (3)然后比较两科子树的深度,取最深的加1,就是当前节点为头节点所在子树的最大深度。

        这不就是“左右中”——后序遍历吗。

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

5.2 方法二:层序遍历

        层序的解决方法就简单粗暴了,我直接一层一层去遍历,直到下一层一个节点都没有了,每遍历一层就+1。

    public int maxDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }
        Deque<TreeNode> deque = new LinkedList<>();
        deque.push(root);
        int height = 0;
        while (!deque.isEmpty()) {
            int size = deque.size();
            height++;
            while (size-- > 0) {
                TreeNode pop = deque.pop();
                if (pop.left != null) {
                    deque.addLast(pop.left);
                }
                if (pop.right != null) {
                    deque.addLast(pop.right);
                }
            }
        }
        return height;
    }

6. 二叉树的最小深度

111. 二叉树的最小深度

        给定一个二叉树,找出其最小深度。最小深度是从根节点到最近叶子节点的最短路径上的节点数量

6.1 方法一:后序遍历

        首先需要这段代码限制一下null为空的情况,root为null深度就为0,返回就好了。

        if(root == null) {
            return 0;
        }

         当前节点左节点为null,右节点也为null,此时这个节点的高度就是1,然后还是采用最大深度的思想,“中”用来收集左右子树最小的深度。

    public int minDepth(TreeNode root) {
        if(root == null) {
            return 0;
        }
        if (root.left == null && root.right == null) {
            return 1;
        }
        int l = Integer.MAX_VALUE;
        if (root.left != null) {
            l = minDepth(root.left);
        }
        int r = Integer.MAX_VALUE;
        if (root.right != null) {
            r = minDepth(root.right);
        }
        return Math.min(l, r) + 1;
    }

6.2 方法二:层序遍历

        在层序遍历的时候,一旦发现哪个节点的左节点为null,右节点也为null,就说明这个节点是叶子节点了。因为是一层一层的遍历,所以一旦第一次碰到叶子节点,这个深度一定就是最小的,直接返回此时记录的深度就好。

    public int minDepth(TreeNode root) {
       if (root == null) {
            return 0;
        }
        Deque<TreeNode> deque = new LinkedList<>();
        deque.push(root);
        int height = 0;
        while (!deque.isEmpty()) {
            int size = deque.size();
            height++;
            while (size-- > 0) {
                TreeNode pop = deque.pop();
                if (pop.left == null && pop.right == null) {
                    return height;
                }
                if (pop.left != null) {
                    deque.addLast(pop.left);
                }
                if (pop.right != null) {
                    deque.addLast(pop.right);
                }
            }
        }
        return height;
    }

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

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

相关文章

使用 preloadComponents 进行组件预加载

title: 使用 preloadComponents 进行组件预加载 date: 2024/8/18 updated: 2024/8/18 author: cmdragon excerpt: 摘要&#xff1a;本文介绍Nuxt 3中的preloadComponents功能&#xff0c;用于预加载全局注册的组件以减少首次渲染阻塞时间&#xff0c;通过实例演示如何设置并…

EmguCV学习笔记 C# 4.2 二值化

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 教程VB.net版本请访问&#xff1a;EmguCV学习笔记 VB.Net 目录-CSDN博客 教程C#版本请访问&#xff1a;EmguCV学习笔记 C# 目录-CSD…

WebRTC音视频开发读书笔记(五)

WebRTC既可以收发音频和视频&#xff0c;还可以传输其它数据&#xff0c;如短消息、二进制数据、文本数据等。可以实现文本聊天、文件传输等场景。 八、数据通道 1、基本概念 WebRTC的数据通道好比高速公路、文本、文件、图像以及其它数据 好比货物&#xff0c;通道打通 &am…

SpringBoot Web请求、响应

一、文章概述 请求方面主要讲&#xff0c;当前端向后端发出请求时&#xff0c;对于不同类型的参数后端都如何接收&#xff1b;对于响应&#xff0c;文章会讲解后端如何向前端响应数据以及如何使返回的数据具有统一的格式。 二、请求 2.1接收简单参数 Controller方法&#xf…

sqlserver的openquery配置

1.命令Demo ---openquery--开启Ad Hoc Distributed Queries组件&#xff0c;在sql查询编辑器中执行如下语句exec sp_configure show advanced options,1reconfigureexec sp_configure Ad Hoc Distributed Queries,1reconfigure--关闭Ad Hoc Distributed Queries组件&#xff0…

10、stm32实现adc读取数据

一、配置 二、代码 /* USER CODE BEGIN 2 */OLED_Init();OLED_Clear();OLED_ShowString(0,0,"Hello adc",12,0);uint16_t adc_number 0;/* USER CODE END 2 *//* USER CODE BEGIN WHILE */while (1){HAL_ADC_Start(&hadc1);HAL_ADC_PollForConversion(&hadc1…

2分钟搭建一个简单的WebSocket服务器

你好同学&#xff0c;我是沐爸&#xff0c;欢迎点赞、收藏和关注。个人知乎 如何用2分钟在本地搭建一个简单的 WebSocket 服务器&#xff1f;其实使用 Node.js&#xff0c;加上一些流行的库&#xff0c;是很容易实现的。前端同学通过自己搭建 WebSocket 服务器&#xff0c;对于…

PyTorch深度学习快速入门教程--学习笔记

目录 P4 PyCharm和Jupyter的对比 P5 PyTorch加载数据 P6 Dataset类代码实现 P7 Tensorboard 写日志 读取日志文件 Tensorboard 读图片 P10 Transforms使用 Transforms用途 常见的Transforms工具 P14 torchvision数据集使用 P15 Dataloader使用 P16 nn.Module模块使…

政务大数据解决方案(三)

政务大数据解决方案致力于通过整合来自不同部门和领域的海量数据&#xff0c;采用先进的数据分析技术与人工智能算法&#xff0c;建立一个全面、高效的数据管理平台&#xff0c;从而优化政府决策过程&#xff0c;提高政策制定的科学性与精准性。该方案涵盖数据采集、存储、处理…

C语言学习笔记 Day14(文件管理)

Day14 内容梳理&#xff1a; 目录 Chapter 10 文件操作 10.0 概述 10.1 打开、关闭文件 &#xff08;1&#xff09;文件指针 &#xff08;2&#xff09;打开文件 fopen() &#xff08;3&#xff09;读取文件 fgetc() &#xff08;4&#xff09;写入文件 fputc() Ch…

Arthas:Java应用诊断利器

1、简介 Arthas 是一款线上监控诊断产品&#xff0c;通过全局视角实时查看应用 load、内存、gc、线程的状态信息&#xff0c;并能在不修改应用代码的情况下&#xff0c;对业务问题进行诊断&#xff0c;包括查看方法调用的出入参、异常&#xff0c;监测方法执行耗时&#xff0c…

【大数据算法】一文掌握大数据算法之:概述、特点、类型及难点等,值得收藏。

大数据算法概述 1、引言2、大数据算法概述2.1 什么是大数据算法2.2 大数据算法特点2.3 大数据算法类型2.4 大数据算法难点 3、总结 1、引言 小屌丝&#xff1a;鱼哥&#xff0c;大数据开篇反馈不错哦。 小鱼&#xff1a;嗯&#xff0c;是的呢&#xff0c; 咱这个专栏&#xff…

Fly Catcher:通过监测恶意信号来检测飞机欺骗

Fly Catcher 的开发者 Angelina Tsuboi 是一名飞行员、网络安全研究员和发明家。 她决定着手一个将这三个不同兴趣结合起来的项目&#xff0c;以解决航空雷达系统的一个重大问题。 ADS-B 系统最初用于基本的飞机定位和跟踪&#xff0c;Tsuboi 对该系统的网络安全方面进行了深…

正点原子阿尔法ARM开发板-IMX6ULL(一)——环境安装和资源介绍

文章目录 一、环境安装二、主目录的资源介绍2.1 alpzha2.2 linux2.3 c_linux 三、QT四、交叉编译五、VScode六、其他6.1 SecureCRT6.2 Putty6.3 MobaXterm6.4 NFS6.5 TFTP 这几天实习的强度下来了&#xff0c;就来看看嵌入式方面的知识了 也是买了正点原子的阿尔法的嵌入式开发…

一次日志记录中使用fastjson涉及到ByteBuffer的教训

背景 目前本人在公司负责的模块中&#xff0c;有一个模块是负责数据同步的&#xff0c;主要是将我们数据产线使用的 AWS Dynamodb 同步的我们的测试QA 的环境的 MongoDB 的库中&#xff0c;去年开始也提供了使用 EMR 批量同步的功能&#xff0c;但是有时候业务也需要少量的数据…

Linux内核分析(RCU机制和内存优化)

文章目录 前言一、RCU概念RCU 的基本概念1. **如何工作**2. **RCU 的工作流程** RCU 的主要优势RCU 的使用场景RCU 的挑战和局限RCU 的实现总结 二、RCU对链表的访问三、Linux中的屏障主要类型应用场景实现作用用途 前言 一、RCU概念 RCU&#xff08;Read-Copy-Update&#x…

【Web】巅峰极客2024 部分题解

目录 EncirclingGame GoldenHornKing php_online admin_Test EncirclingGame 玩赢游戏就行 GoldenHornKing 利用点在传入的app 可以打python内存马 /calc?calc_reqconfig.__init__.__globals__[__builtins__][exec](app.add_api_route("/flag",lambda:__i…

【数据结构】二叉树(三)精选Oj题

本篇已经是二叉树第三篇啦&#xff0c;下面讲解相关面试题&#xff0c;写作不易&#xff0c;求路过的朋友给个点赞与收藏呀~ 目录 1、相同的树 2、另一颗树的子树 3、翻转二叉树 4、对称二叉树 5、平衡二叉树 6、构建二叉树 7、二叉树的最近公共祖先 孩子双亲解法 二叉…

企业为何需要渗透测试

随着数字化时代的全面到来&#xff0c;互联网已成为企业运营不可或缺的一部分。然而&#xff0c;日益复杂的网络环境和不断演变的攻击手段&#xff0c;使得网络安全问题日益严峻。在这一背景下&#xff0c;渗透测试作为一种重要的安全评估手段&#xff0c;对于保障企业信息安全…

day24-测试之接口测试基础

目录 一、接口的定义 二、接口的优点 三、API接口 四、接口测试流程 五、网络基础概念 六、HTTP和RURL 七、get和post请求 八、数据格式 九、状态码 十、restful风格 十一、接口工具 一、接口的定义 程序之间协作所要遵循的一套规范、标准 二、接口的优点 2.1.责任…