算法题解记录24+++二叉树的右视图(百日筑基)

题目描述:

        题目难度:中等

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

示例 1:

输入: [1,2,3,null,5,null,4]
输出: [1,3,4]

示例 2:

输入: [1,null,3]
输出: [1,3]

示例 3:

输入: []
输出: []

提示:

  • 二叉树的节点个数的范围是 [0,100]
  • -100 <= Node.val <= 100

解题准备:

        1.题意:题目要求,我们需要得到树的右视图,那么,右视图是什么?如果依照例图,则展现为【1,3,4】,如果节点5的下面有一子节点6呢?那么就应该是【1,3,4,6】,如果节点5,有左子节点6,右子节点7,则展示为【1,3,4,7】(也就是说,我们不能一直root.right,得到所有的右子节点,称它们为右视图。)

        2.基本操作:题目只是拿到一个视图,一般来说不会修改数据,所以认为只存在“查找”

        3.基础原理:对于二叉树的算法,很可能会使用BFS或者DFS,也有可能是BFS或者DFS的变种。对DFS、BFS的原理在此不赘述。

解题思路:

        如果一上来就用BFS,那么很容易就解开了,这道题对于你已经属于很简单了,可以不必看。

        从初学者的角度出发,我们一开始没有列出BFS,甚至不知道BFS,更夸张点,我们连DFS都不知道,那该怎么办?

        最朴素的思路,可以是先用root.right迭代,一直得到所有最右节点【比如本例的1,3,4】,然后,对后续的每一层,进行遍历,拿到其所有节点,并判断谁更靠右。

        朴素的思路---迭代后,依靠深度拿值

                假设一棵树深度为D。

                第一步,用root.right,一直迭代,直到拿到最右节点“4”,至少此时,你的前x层都拿到了最右的节点。

                第二步,求出深度D,此时,你只需要拿到,接下来的D-x层的最右节点,就可以解决此问题。

                第三步,好像没有思路了。

                我们发现,有2个难点:其一,如果我们拿到了2个同一层级的节点,如何判断二者的左右顺序呢?其二,我们如何拿到同一层级的所有节点呢?

                二叉树结构里,不会特意标注层级,也不会特意标注左右顺序。

                从学习的角度出发,如果我们一条思路堵住,并且一阵子内没有衍生出第二条、第三条思路,那么就可以翻看答案了,当然,我们知道有DFS深度优先遍历算法的存在。

        优化思路---深度优先遍历算法,代替麻烦的求层级

                我们知道,前序遍历算法,第一个出现的,一定是树的根,其次是左子树,然后是右子树。比如下图【其实也就是上述的结构】:

                它的前序遍历就是:【1,2,5,6,7,3,4】

                可以看出,1、3、4、7是我们需要的解题答案,但是却很难得出这个结果。

                因为这个序列中,最右子节点的出现没什么规律,1出现在首位,4出现在末位,7出现在中间,甚至如果在节点4下,添加节点8,那么7就不是答案,而8却同样出现在末位。

                不过,我们却能发现最左节点的规律:在每一层中,永远第一个出现。

                比如【1,2,5,6】恰好都是最左节点,并且在其层级,第一个出现,比如:

                1--在0层中最左,并且第一个出现。

                2--在1层中最左……

                5--在2……

                同理,假如为2添加一左子节点X,会发生什么?

                前序序列:【1,2,X,5,6,7,3,4】

                其随着节点顺序不同而变化。

                同时,我们知道,前序遍历的本质,就是先访问根节点,再访问左子树,然后是右子树。

                如果修改一下顺序,先访问根节点,再访问右子树,最后才是左子树,会不会有一样的规律呢?

                在此不证明,不过确实是这样,因此我们解决了顺序的问题。

                下一个问题是,我们如何确定出现的某个节点,是哪个层级的呢?

                如果用编写另一个函数,用dfs重新判断层级,不失为一种方向,不过太麻烦,复杂度也比较高。

                从树的性质来说,如果一个节点X的深度是depth,那么,它的子节点的深度都是depth+1。

                也就是说,只要我们知道根节点root的深度为0,就能通过递归,简单地推出树下所有节点的深度。

                不过,知道了节点层级、相互顺序,麻烦又来了:

                我如何得到,你这一层,你是第一个出现的节点的结论?

                如果我们采用一个List,存储TreeNode的dfs顺序【右子树的顺序】及其层级,就能通过之后的遍历,依次得到最右节点。

                可是,这种方式占用了一些空间,不是最优方案,不过肯定可行。

                这个问题的答案,我放在解题难点分析中讲解。

        优化思路---BFS广度优先遍历算法,连求层级都省了

                其实BFS思路非常简单,就是先遍历根节点root,然后将root.left添加到一个队列que中,再把root.right添加到队列que中。

                接着,遍历que中所有节点X,同时把节点X的左子节点、右子节点按顺序添加到que中。

                在每一层遍历时,只需要到最后,把节点添加到结果集中即可。

                【当然,也可以先把right右节点添加到队列,这样,只需要在遍历初始,把节点添加到结果集即可】

                不过,其虽然思路简单,写起代码却有一些问题,比如:我们一般会用nodeList非空作为循环判断条件,但是nodeList在拿出一个元素Elem的同时,也在把Elem的左右子节点添加到nodeList当中,该怎么办?这部分内容,我放到解题难点分析中讲解。

解题难点分析:

        第一,dfs如何节省空间地拿到第一个出现的最右节点maxRight。

                我们已经知道maxRight每次都会出现在第一位,并且已经有其层级数据。

                那么,我们可以用一个HashMap,当该层级不存在节点时,说明出现的元素,就是第一个最右节点!【这是互为充要的条件】

        第二,bfs如何避免诡异的while循环

                当我们将root添加到队列que中时,不可避免地需要用while(!nodeList.isEmpty())来判断队列中还有无元素。如果用for来迭代que的size,则本质类似。

                所以,不能单独用while或for解决,可以考虑结合。

                对于que,我们希望它存储的是某一层级的所有节点,并且没有其它层级的节点,这样,在访问时不会访问到其它节点。

                如果用朴素的方法,就是借用辅助队列fQ,在访问que时,将下一层级元素添加到fQ中,下一次循环,再将fQ元素复制到que中,这样节省了判断。

                不过,有点浪费空间和时间。

                我们知道,在访问开始前,que中只有root一个元素,如果只访问root,那么下一刻,que中可能存在左子、右子两个元素,这时,它们仍是同一层级元素,并且是所有的第1层级元素。

                如果只访问左子、右子,那么,下一刻,que可能存在左子的左右子、右子的左右子4个元素,同理,这都是同一层级的所有第2级元素。

                发现了吗,如果限制访问个数,每次只访问开始前que的size大小的元素,就可以避免访问到下一层级的元素。

                所以,用while判断que中剩余元素否,用for依次遍历。

        第三,bfs如何添加maxRight到结果集

                简单地说,我们只需要最后一个元素,也就是说,当for循环,i指向size-1时,就可以添加到结果集。

dfs代码:

class Solution {Map<Integer, Integer> temp; // 放在这里,可以节省一个变量public List<Integer> rightSideView(TreeNode root) {List<Integer> res; // 存储结果temp = new HashMap<>(); dfs(root, 0); // 最初是深度0,且是根节点// 这一步,是把map的value元素,转化为listres = new ArrayList<>(temp.values());return res;}private void dfs(TreeNode root, int depth){if(root==null){return;}// 如果不存在该层级的元素,则添加if(!temp.containsKey(depth)){temp.put(depth, root.val);}// 遍历下一层级。depth++;dfs(root.right, depth);dfs(root.left, depth);}
}

bfs代码:

class Solution {public List<Integer> rightSideView(TreeNode root) {List<Integer> res = new ArrayList<>();Queue<TreeNode> nodeList = new LinkedList<>();// 访问null会导致异常,所以特殊对待if(root==null){return res;}nodeList.add(root);// 遍历while(!nodeList.isEmpty()){int size = nodeList.size();// 每次遍历size大小for(int i=0; i<size; i++){TreeNode temp = nodeList.poll();// 避免访问到nullif(temp.left!=null){nodeList.add(temp.left);}if(temp.right!=null){nodeList.add(temp.right);}// 这表示访问到最后一个元素if(i==size-1){res.add(temp.val);}}}return res;}
}

以上内容即我想分享的关于力扣热题24的一些知识。

        我是蚊子码农,如有补充,欢迎在评论区留言。个人也是初学者,知识体系可能没有那么完善,希望各位多多指正,谢谢大家。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

picoCTF-Web Exploitation-Trickster

Description I found a web app that can help process images: PNG images only! 这应该是个上传漏洞了&#xff0c;十几年没用过了&#xff0c;不知道思路是不是一样的&#xff0c;以前的思路是通过上传漏洞想办法上传一个木马&#xff0c;拿到webshell&#xff0c;今天试试看…

【C/C++】C/C++ 车票售票系统设计与实现(源码+课件)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

Linux部署

先把需要的东西准备好&#xff1a; 第一步解压tomcat&#xff1a; tar -zxvf apache-tomcat-8.5.20.tar.gz 第二步解压jdk: tar -zxvf jdk-8u151-linux-x64.tar.gz 第三步配置Java环境变量&#xff1a; vim /etc/profile 把下面代码放进去&#xff1a; export JAVA_HOME/root…

【解决】:git clone项目报错fatal: fetch-pack: invalid index-pack output

象&#xff1a;之前一直使用gitee将个人学习和工作相关记录上传到个人gitee仓库&#xff0c;一直没出现过问题。直到有一天换电脑重新拉取代码发现出了问题&#xff0c;具体如下图&#xff1a; 原因分析&#xff1a; 经过查询发现主要原因是因为git clone的远程仓库的项目过大…

台阶仪测量膜厚原理及优势

台阶仪&#xff0c;也称为探针式轮廓仪或接触式表面轮廓测量仪&#xff0c;主要用于台阶高、膜层厚度、表面粗糙度等微观形貌参数的测量。 台阶仪的工作原理 台阶仪的核心部件是一个精密的触针或探针&#xff0c;它被安装在一个高度可调的支架上。当触针沿被测表面轻轻滑过时…

搭建 IIS + asp +access 网站

搭建 IIS asp access 网站 一、什么是 asp二、asp 的组成三、asp 说明四、什么是access五、搭建环境六、问题一七、问题二八、网站展示九、IIS 页面展示十、IIS 功能展示 欢迎关注公总号【云边小网安】 一、什么是 asp asp&#xff1a;即 Active Server Pages&#xff0c;是…

14.跳跃游戏Ⅱ

文章目录 题目简介题目解答解法一&#xff1a;贪心算法动态规划代码&#xff1a;复杂度分析&#xff1a; 题目链接 大家好&#xff0c;我是晓星航。今天为大家带来的是 跳跃游戏Ⅱ 相关的讲解&#xff01;&#x1f600; 题目简介 题目解答 解法一&#xff1a;贪心算法动态规划…

Line Buffer概述

buffer在芯片物理上一般指的是SRAM&#xff0c;也可以指寄存器组。buffer的作用是用来在逻辑芯片上暂时存储数据&#xff0c;但不会是大量的数据。如果是大量数据一般会使用DRAM&#xff08;典型的指DDR&#xff09;作为存储芯片&#xff0c;用来存储大密度数据。line buffer可…

Linux开发--Linux内核开发移植

Linux内核开发移植 Linux内核版本变迁及其获得 Linux是最受欢迎的自由电脑操作系统内核&#xff0c; 是一个用C语言写成&#xff0c; 并且符合POSIX标准的类Unix操作系统 Linux是由芬兰黑客Linus Torvalds开发的&#xff0c; 目的是尝试在英特尔x86架构上提供自由免费的类Un…

英语复习之英语形近词总结(四)

英语形近词总结复习第四部分&#xff1a; 单词 释义例句 genuine 英 /ˈdʒenjuɪn/ 美 /ˈdʒenjuɪn/ adj.真实的&#xff0c;真正的&#xff1b;诚恳的 1.Only genuine refugees can apply for asylum. 只有真正的难民才能申请政治避难。 《牛津词典》 2.This isnt a genui…

牛客NC343 和大于等于K的最短子数组【困难 前缀和 Java/Go】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/3e1fd3d19fb0479d94652d49c7e1ead1 思路 本答案利用前缀和解答&#xff0c;Java&#xff0c;Go答案通过&#xff0c;但是同样的代码用PHP的话有一个测试用例超时 应该还有更优秀的答案&#xff0c;后面找到更优…

QT6 android程序界面强制横屏显示不旋转

QT6开发的Android程序有时候旋转后程序会变形&#xff0c;比如想让其固定位横屏显示&#xff0c;就需要进行特殊设置&#xff0c;本文提供一种简便的设置方法。 一.AndroidManifest.xml文件介绍 Android的Manifest.xml文件是一个重要的配置文件&#xff0c;用于描述应用程序的…