LeetCode刷题日记之二叉树(六)

目录

  • 前言
  • 二叉搜索树中的众数
  • 二叉树的最近公共祖先
  • 二叉搜索树的最近公共祖先
  • 总结


前言

又是学习LeetCode二叉树的新一天,今天还是接着学习一下二叉搜索树的内容,希望博主记录的内容能够对大家有所帮助 ,一起加油吧朋友们!💪💪💪


二叉搜索树中的众数

LeetCode题目链接

给一个含重复值的二叉搜索树的根节点root,返回该树的所有众数(以数组格式)
请添加图片描述

思路梳理:这道题其实也是可以利用二叉搜素数中序遍历节点值递增的规律来写,因为就是可以在递归遍历的时候去更新当前节点频率和最大节点频率来完成这样,当当前节点频率大于等于最大节点频率时就把当前节点的值加入到一个整数列表中🤔🤔🤔

我们接下来梳理递归三要素

  • 确定递归的参数和返回值
// 定义了结果的列表所以无需返回值,然后前序节点值和当前频率、最大频率用变量保存故参数只有数的根节点即可
private void inOrderTraversal(TreeNode root){}
  • 确定递归的出口
//因为要处理每个节点所以会进入空节点
if(root == null) return;
  • 确定递归的单层逻辑
//递归单层处理逻辑
inOrderTraversal(root.left);// 递归遍历左子树

if(root.val == preVal){ // 处理当前节点
    curCount++;
}else{
    curCount = 1;
}

if(curCount > maxCount){  // 判断是否需要更新众数列表
    maxCount = curCount;
    result.clear();
    result.add(root.val);
}
else if(curCount == maxCount){// 如果当前频率等于最大频率也加入到众数列表中
    result.add(root.val);
}
preVal = root.val;// 更新前一个节点的值为当前值


inOrderTraversal(root.right);// 递归遍历右子树

完整代码如下

/**递归法 */
class Solution {
    private int maxCount = 0; //最大频率
    private int curCount = 0;//当前频率
    private int preVal = Integer.MIN_VALUE;//记录前一个节点的值
    private List<Integer> result = new ArrayList<>();//记录众数结果
    public int[] findMode(TreeNode root) {
        inOrderTraversal(root);
        return result.stream().mapToInt(Integer::intValue).toArray();
    }

    private void inOrderTraversal(TreeNode root){ //中序遍历
        //递归出口
        if(root == null) return;

        //递归单层处理逻辑
        inOrderTraversal(root.left);

        if(root.val == preVal){ //更新频率
            curCount++;
        }else{
            curCount = 1;
        }

        if(curCount > maxCount){ //更新众数
            maxCount = curCount;
            result.clear();
            result.add(root.val);
        }
        else if(curCount == maxCount){
            result.add(root.val);
        }
        preVal = root.val;//更新存储的前节点的值


        inOrderTraversal(root.right);
        
    }
}

这里可以提一下的是最后将列表转换成整型数组的一步操作

return result.stream().mapToInt(Integer::intValue).toArray();
  • .stream()是java 8引入的Stream API中的一个方法,用于从集合( 如 ListSetMap 等)或数组生成一个流(Stream)🤔
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.stream()  // 生成流
     .filter(name -> name.startsWith("A"))  // 过滤出以"A"开头的名字
     .forEach(System.out::println);  // 输出满足条件的名字
  • mapToInt() 是 Java Stream API 提供的用于将流中的对象映射为基本类型的方法,类似的方法还有mapToDouble()mapToLong()等。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
int[] result = numbers.stream()
                      .mapToInt(Integer::intValue) // 将 Integer 转换为 int
                      .toArray(); // 转换为 int[]
// result 是 [1, 2, 3, 4]
  • intValue()Integer 类的一个方法,它的作用是将 Integer 对象转换为基本数据类型 int。在 Java 中,包装类(如 IntegerDouble 等)都有类似的转换方法,将包装类的对象转换为对应的基本数据类型。
result.stream().mapToInt(Integer::intValue).toArray();
result.stream().mapToDouble(Double::doubleValue).toArray();
result.stream().mapToLong(Long::longValue).toArray();

我们也来梳理一下迭代法

  • 主要就是中序遍历需要先把root节点压栈,然后把左子树节点递归入栈,然后弹出root节点进行处理,处理完后递归处理右节点,处理的逻辑和递归一样,然后的话就是栈一开始为空,循环条件加上一个当前节点不为空,而当前节点初始化为root🤔🤔🤔
/**迭代法 */
class Solution {
    public int[] findMode(TreeNode root) {
         int maxCount = 0; //最大频率
         int curCount = 0;//当前频率
         int preVal = Integer.MIN_VALUE;//记录前一个节点的值
         List<Integer> result = 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{
                cur = stack.pop(); //弹出中节点
                if(cur.val == preVal){
                    curCount++;
                }else{
                    curCount = 1;
                }

                if(curCount > maxCount){
                    maxCount = curCount;
                    result.clear();
                    result.add(cur.val);
                }else if(curCount == maxCount){
                    result.add(cur.val);
                }
                preVal = cur.val;
                cur = cur.right;//处理右节点
            }
         }
         return result.stream().mapToInt(Integer::intValue).toArray();
    }

    
}

二叉树的最近公共祖先

LeetCode题目链接

给定一个二叉树,找到该树中两个指定节点的最近公共祖先
请添加图片描述

我们来进行思路梳理🤔🤔🤔

  • 首先的话就是找最近公共祖先我们需要从底向上遍历二叉树,所以只能通过后序遍历(左右中)来实现从底向上遍历🤔🤔🤔
递归函数返回值 递归函数(递归参数给定节点p,递归参数给定节点q,递归参数二叉树根节点root){
	//递归出口
	//处理左子树
	//处理右子树
	//处理中间父结点
}
  • 接着的话最重要的就是怎么判断中间父结点是不是给定节点p和q的最近公共祖先呢🤔🤔🤔,如果左子树与右子树分别找到q/p则当前root就是最近的公共祖先
    请添加图片描述

  • 那有人会说了如果root是q/p呢,这个就属于递归出口的判断逻辑了,首先我们会判断每个节点也必然会进行空节点判断所以递归出口有if(root == null)return null;,如果root为q/p那么也得返回找到的root节点然后呢?🤔🤔🤔接着往其左右子树去找剩下的节点能不能找到

TreeNode 递归函数(递归参数给定节点p,递归参数给定节点q,递归参数二叉树根节点root){
	if(root == q || root == p || root == null) return root;//递归出口
	//处理左子树
	//处理右子树
	//处理中间父结点
}

思路梳理完毕后我们来紧接着梳理递归三要素🤔🤔🤔

  • 确定递归函数的参数和返回值
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {}
  • 确定递归出口
if(root == q || root == p || root == null) return root;
  • 确定递归的单层处理逻辑
/**单层处理逻辑 */
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);//后序遍历
if(left != null && right != null) return root;
if(left == null) return right;
return left;

递归法java代码如下

/**递归法 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == q || root == p || root == null) return root;

        /**单层处理逻辑 */
        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);//后序遍历
        if(left != null && right != null) return root;
        if(left == null) return right;
        return left;
    }
}

我们接着来梳理迭代法的思路🤔🤔🤔

  • 我们可以利用栈进行深度优先搜索来遍历二叉树,同时记录每个节点的父结点信息以便在找到p/q节点时能够追溯路径🤔🤔🤔
HashMap<TreeNode,TreeNode> parentMap = new HashMap<>();//哈希表存储每个节点的父节点
  • 找到p和q节点时遍历其中一个节点的路径,返回第一个相交的节点作为最近公共祖先🤔🤔🤔
HashSet<TreeNode> ancestors = new HashSet<>();//准备处理p/q节点的全部父节点路径
while(p != null){ //列出p的所有祖先节点
    ancestors.add(p);
    p = parentMap.get(p);
}

while(!ancestors.contains(q)){//查找p的所有祖先节点中的第一个公共祖先
    q = parentMap.get(q);
}

return q;

完整迭代法代码如下

/**迭代法 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null) return null;//提前结束
        HashMap<TreeNode,TreeNode> parentMap = new HashMap<>();//哈希表存储每个节点的父节点
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);//准备前序遍历
        parentMap.put(root, null); //根节点没有父结点

        while(!parentMap.containsKey(q) || !parentMap.containsKey(p)){ //直到路径找到p和q
            TreeNode cur = stack.pop();

            if(cur.left != null){//处理左子树
                parentMap.put(cur.left, cur);
                stack.push(cur.left);
            }

            if(cur.right != null){//处理右子树
                parentMap.put(cur.right, cur);
                stack.push(cur.right);
            }
        }

        HashSet<TreeNode> ancestors = new HashSet<>();//准备处理p/q节点的全部父节点路径
        while(p != null){ //列出p的所有祖先节点
            ancestors.add(p);
            p = parentMap.get(p);
        }

        while(!ancestors.contains(q)){//查找p的所有祖先节点中的第一个公共祖先
            q = parentMap.get(q);
        }

        return q;
    }

二叉搜索树的最近公共祖先

LeetCode题目链接

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先
请添加图片描述

我们来进行思路梳理🤔🤔🤔

  • 首先的话就是找最近公共祖先我们需要从底向上遍历二叉树,所以只能通过后序遍历(左右中)来实现从底向上遍历,这个逻辑不变🤔🤔🤔

  • 接着的话最重要的就是怎么判断中间父结点是不是给定节点p和q的最近公共祖先呢🤔🤔🤔,如果左子树与右子树分别找到q/p则当前root就是最近的公共祖先,对于二叉搜索树的话,根节点的值大于左子树的值小于右子树的值,所以我们可以得到要找的最近公共祖先就是数组在[q.val, p.val]或者[p.val, q.val]之中

ok,我们直接梳理递归三要素

  • 确定递归参数和返回值
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {}
  • 确定递归出口
if(root == null) return root;
  • 确定单层处理逻辑
if(root.val > q.val && root.val > p.val){
	return lowestCommonAncestor(root.left, p, q);//往左找
} else if(root.val < q.val && root.val < p.val){
    return lowestCommonAncestor(root.right, p, q);//往左找
}else{
    return root;//找到了
}

总的递归代码如下

/**递归法 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null) return root;
        if(root.val > q.val && root.val > p.val){
	        return lowestCommonAncestor(root.left, p, q);//往左找
        } else if(root.val < q.val && root.val < p.val){
            return lowestCommonAncestor(root.right, p, q);//往左找
        }else{
            return root;//找到了
        }
    }
}

我们接着来梳理迭代法的逻辑🤔🤔🤔

  • 由于二叉搜索树的性质,我们递归本质上是去找一个数值介于p与q数值之间的节点,所以我们迭代法无需栈或者队列来存储节点🤔🤔🤔

迭代法代码如下

/**迭代法 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        while(root != null){
            if(root.val > q.val && root.val > p.val) {
                root = root.left;
            }else if(root.val < q.val && root.val < p.val){
                root = root.right;
            }else{
                return root;
            }
        }
        return null;
    }
}

总结

国庆假期结束,开始加油啦✊✊✊

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode讲解篇之2466. 统计构造好字符串的方案数

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 组成长度为i的字符串个数 组成长度为i - zero的字符串个数 组成长度为i - one的字符串个数 设数组f中i号元素的值为组成长度为i的字符串个数 则状态转移方程为f[i] f[i - zero] f[i - one]&#xff0c;其中需…

MySQL中NULL值是否会影响索引的使用

MySQL中NULL值是否会影响索引的使用 为何写这一篇文章 &#x1f42d;&#x1f42d;在面试的时候被问到NULL值是否会走索引的时候&#xff0c;感到有点不理解&#xff0c;于是事后就有了这篇文章 问题&#xff1a; 为name建立索引&#xff0c;name可以为空select * from user …

使用标签实现MyBatis的基础操作

目录 前言 1.配置MyBatis⽇志打印 2.参数传递 2.1 #{} 和 ${}区别 2.2传递多个参数 3.增删改查 3.1增(Insert) 3.2删(Delete) 3.3改(Update) 3.4查(Select) 前言 接下来我们会使用的数据表如下&#xff1a; 对应的实体类为&#xff1a;UserInfoMapper 所有的准备工作都…

Nginx08-反向代理

零、文章目录 Nginx08-反向代理 1、概述 关于正向代理和反向代理&#xff0c;我们在前面已经介绍过了&#xff0c;简而言之就是正向代理代理的对象是客户端&#xff0c;反向代理代理的是服务端&#xff0c;这是两者之间最大的区别。 Nginx即可以实现正向代理&#xff0c;也可…

Python进阶--正则表达式

目录 1. 基础匹配 2. 元字符匹配 1. 基础匹配 正则表达式&#xff0c;又称规则表达式&#xff08;Regular Expression&#xff09;&#xff0c;是使用单个字符串来描述、匹配某个句法规则的字符串&#xff0c;常被用来检索、替换那些符合某个模式&#xff08;规则&#xff…

爱心曲线公式大全

local r a*((math.sin(angle) * math.sqrt(math.abs(math.cos(angle)))) / (math.sin(angle) 1.4142) - 2 * math.sin(angle) 2) local x r * math.cos(angle) -- 计算对应的x值 local z r * math.sin(angle) 1.5*a - --曲线公式绘画 local function generateParabola()…

【异常记录Vue_20241006】使用TagsView后控制台报错

报错截图 报错原因 未将TagsView所依赖的组件permission组件注册到store中&#xff0c;导致TagsView组件在找permission.routes时没找到 解决方法&#xff1a;store注册相应组件

应用界面编写(十四)

一. 介绍QT 接下来我们会在Qt Creater来进行界面的编写&#xff0c;并且在荔枝派中运行。那么我们有必要了解一下Qt到底是什么呢&#xff1f;它又为什么可以在荔枝派中运行呢&#xff1f; QT是一个跨平台的应用程序和用户界面框架&#xff0c;用于开发具有图形界面的软件。而…

【AI知识点】残差网络(ResNet,Residual Networks)

残差网络&#xff08;ResNet&#xff0c;Residual Networks&#xff09; 是由微软研究院的何凯明等人在 2015 年提出的一种深度神经网络架构&#xff0c;在深度学习领域取得了巨大的成功。它通过引入残差连接&#xff08;Residual Connection&#xff09; 解决了深层神经网络中…

Linux--IO模型与高级IO重要概念

什么是IO&#xff1f; IO是指计算机系统与外部世界进行数据交换的过程。在计算机中&#xff0c;IO通常用于与外部设备通信&#xff0c;这些设备包括键盘、鼠标、打印机、显示器、网络等。通过IO操作&#xff0c;计算机系统可以接收来自外部设备的输入数据&#xff0c;也可以将…

CSS圆角

在制作网页的过程中&#xff0c;有时我们可能需要实现圆角的效果&#xff0c;以前的做法是通过切图&#xff08;将设计稿切成便于制作成页面的图片&#xff09;&#xff0c;使用多个背景图像来实现圆角。在 CSS3 出现之后就不需要这么麻烦了&#xff0c;CSS3 中提供了一系列属性…

代数结构基础 - 离散数学系列(八)

目录 1. 群&#xff08;Group&#xff09; 群的定义 群的示例 2. 环&#xff08;Ring&#xff09; 环的定义 环的示例 3. 域&#xff08;Field&#xff09; 域的定义 域的示例 域在密码学中的应用 4. 实际应用场景 1. 对称性与加密 2. 误差检测与纠正 3. 数据编码…

jetlinks物联网平台学习5:dtu设备接入及温度报警场景联动

dtu设备接入及温度报警场景联动 1、平台端配置1、新建协议2、新建网络组件3、设备接入网关配置4、新增产品5、导入产品物模型6、新增设备7、场景联动配置7.1、触发规则7.2、触发条件7.3、执行动作 2、平台端验证场景联动 1、平台端配置 下载三个文件 https://hanta.yuque.com…

40条经典ChatGPT论文指令,圈定选题和进行论文构思

目录 1、用ChatGPT圈定选题范围2、用ChatGPT生成研究方法和思路3、用ChatGPT扩展论文观点和论证4、用ChatGPT辅助论文结构设计5、如何直接使用ChatGPT4o、o1、OpenAI Canvas6、OpenAI Canvas增强了啥&#xff1f;7、编程功能增强 &#x1f447; ChatGPT o1网页入口在文末&#…

如何让算法拥有“记忆”?一文读懂记忆化搜索

✨✨✨学习的道路很枯燥&#xff0c;希望我们能并肩走下来! 文章目录 目录 文章目录 前言 一 什么是记忆化搜索 二 相关题目练习 2.1 斐波那契数&#xff08;详解记忆化搜索&#xff09; ​编辑 解法一&#xff08;递归&#xff09;&#xff1a; 解法二&#xff08;记…

免费高可用软件

高可用软件是指那些能够提供高可用性、高可靠性的软件&#xff0c;它们在各种应用场景下都能确保系统的稳定运行。以下是四款免费的高可用软件&#xff0c;它们在不同领域都表现出色&#xff0c;能够满足各种高可用性需求。 一、PanguHA PanguHA是一款专为Windows平台设计的双…

【吊打面试官系列-MySQL面试题】试述视图的优点?

大家好&#xff0c;我是锋哥。今天分享关于【试述视图的优点&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; 试述视图的优点&#xff1f; (1) 视图能够简化用户的操作 (2) 视图使用户能以多种角度看待同一数据&#xff1b; (3) 视图为数据库提供了一定程度的…

一、机器学习算法与实践_06迭代法和KMeans、线性回归、逻辑回归算法笔记

0 迭代法 迭代法不仅是机器学习、深度学习的核心&#xff0c;也是整个人工智能领域的重要概念&#xff0c;其对于算法的设计和实现至关重要 0.1 适合场景 对于不能一次搞定的问题&#xff0c;将其分成多步来解决&#xff0c;逐步逼近解决方案 0.2 典型应用 KMeans 聚类算法…

基于SpringBoot博物馆游客预约系统【附源码】

基于SpringBoot博物馆游客预约系统 效果如下&#xff1a; 主页面 注册界面 展品信息界面 论坛交流界面 后台登陆界面 后台主界面 参观预约界面 留言板界面 研究背景 随着现代社会的快速发展和人们生活水平的提高&#xff0c;文化生活需求也在日益增加。博物馆作为传承文化、…

关于CSS 案例_新闻内容展示

新闻要求 标题:居中加粗发布日期: 右对齐分割线: 提示, 可以使用 hr 标签正文/段落: 左侧缩进插图: 居中显示 展示效果 审核过不了&#xff0c;内容没填大家将就着看吧。 代码 <!DOCTYPE html> <html lang"en"> <head><meta charset&qu…