代码随想录算法训练营第二十一天| 530. 二叉搜索树的最小绝对差、501. 二叉搜索树中的众数、236. 二叉树的最近公共祖先

[LeetCode] 530. 二叉搜索树的最小绝对差

[LeetCode] 530. 二叉搜索树的最小绝对差 文章解释

[LeetCode] 530. 二叉搜索树的最小绝对差 视频解释

题目:

给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值

差值是一个正数,其数值等于两值之差的绝对值。

示例 1:

输入:root = [4,2,6,1,3]
输出:1

示例 2:

输入:root = [1,0,48,null,null,12,49]
输出:1

提示:

  • 树中节点的数目范围是 [2, 104]
  • 0 <= Node.val <= 10^5

[LeetCode] 530. 二叉搜索树的最小绝对差

自己看到题目的第一想法

    先看了一眼文章解释, 被一句话点醒了~

看完代码随想录之后的想法

    看到的第一句话就是: 二叉搜索树右子树节点的值都是大于等于左子树节点以及跟节点的值的. 这样的话就会立刻想起来, 一棵二叉搜索树的中序遍历序列是一个非递减的有序序列. 这样只需要在遍历的过程中,记录当前节点和前一个节点的差, 记录下最小的值即可.

/*** Definition for a binary tree node.* public class TreeNode {*     int val;*     TreeNode left;*     TreeNode right;*     TreeNode() {}*     TreeNode(int val) { this.val = val; }*     TreeNode(int val, TreeNode left, TreeNode right) {*         this.val = val;*         this.left = left;*         this.right = right;*     }* }*/
// 递归法: 
//   核心思想: 对于一个二叉搜索树, 中序遍历后, 遍历的序列是递增的.
class Solution {private TreeNode preNode;private int minmumDifference = -1;public int getMinimumDifference(TreeNode root) {if (root == null) {return -1;}int leftTreeMinimumDifference = getMinimumDifference(root.left);if (preNode != null && (minmumDifference == -1 || root.val - preNode.val < minmumDifference)) {minmumDifference = root.val - preNode.val;}preNode = root;int rightTreeMinimumDifference = getMinimumDifference(root.right);if (leftTreeMinimumDifference >= 0) {minmumDifference = Math.min(leftTreeMinimumDifference, minmumDifference);}if (rightTreeMinimumDifference >= 0) {minmumDifference = Math.min(rightTreeMinimumDifference, minmumDifference);}return minmumDifference;}
}
/*** Definition for a binary tree node.* public class TreeNode {*     int val;*     TreeNode left;*     TreeNode right;*     TreeNode() {}*     TreeNode(int val) { this.val = val; }*     TreeNode(int val, TreeNode left, TreeNode right) {*         this.val = val;*         this.left = left;*         this.right = right;*     }* }*/
// 迭代法: 这里用了前中序遍历统一风格法.
//   核心思想: 对于一个二叉搜索树, 中序遍历后, 遍历的序列是递增的.
class Solution {public int getMinimumDifference(TreeNode root) {Stack<TreeNode> nodes = new Stack<>();TreeNode node = null;int lastNodeVal = -1;int minmumDifference = -1;nodes.push(root);while (!nodes.isEmpty()) {node = nodes.pop();if (node != null) {if (node.right != null) {nodes.push(node.right);}nodes.push(node);nodes.push(null);if (node.left != null) {nodes.push(node.left);}} else {node = nodes.pop();if (lastNodeVal != -1 && (minmumDifference == -1 || node.val - lastNodeVal < minmumDifference)) {minmumDifference = node.val - lastNodeVal;}lastNodeVal = node.val;}}return minmumDifference;}
}

自己实现过程中遇到哪些困难

    无

[LeetCode] 501. 二叉搜索树中的众数

[LeetCode] 501. 二叉搜索树中的众数 文章解释

[LeetCode] 501. 二叉搜索树中的众数 视频解释

题目:

给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。

如果树中有不止一个众数,可以按 任意顺序 返回。

假定 BST 满足如下定义:

  • 结点左子树中所含节点的值 小于等于 当前节点的值
  • 结点右子树中所含节点的值 大于等于 当前节点的值
  • 左子树和右子树都是二叉搜索树

示例 1:

输入:root = [1,null,2,2]
输出:[2]

示例 2:

输入:root = [0]
输出:[0]

提示:

  • 树中节点的数目在范围 [1, 104]
  • -105 <= Node.val <= 105

进阶:你可以不使用额外的空间吗?(假设由递归产生的隐式调用栈的开销不被计算在内)

[LeetCode] 501. 二叉搜索树中的众数

自己看到题目的第一想法

    1. 看到二叉搜索树, 第一反应就是中序是递增或者递减的.

    2. 既然遍历后的序列是递增的, 那么只要拿 number 记录上一个数字, 拿 count 记录当前数字出现的次数, 同时用 maxCount 表示当前出现次数最大的数字出现的次数. 如果 count 比 maxCount 大则要清空结果列表 List<Integer> 后添加, 如果 count == maxCount, 则直接添加到结果列表 List<Integer> 中.

    3. 通过中序遍历数组.

看完代码随想录之后的想法

/*** Definition for a binary tree node.* public class TreeNode {*     int val;*     TreeNode left;*     TreeNode right;*     TreeNode() {}*     TreeNode(int val) { this.val = val; }*     TreeNode(int val, TreeNode left, TreeNode right) {*         this.val = val;*         this.left = left;*         this.right = right;*     }* }*/
class Solution {private List<Integer> result = new ArrayList<>();private int maxCount = 0;private int number = 0;private int count = 0;public int[] findMode(TreeNode root) {findModeRecursion(root);int[] resultArray = new int[result.size()];for (int i = 0; i < result.size(); ++i) {resultArray[i] = result.get(i);}return resultArray;}public void findModeRecursion(TreeNode root) {if (root.left != null) {// 最早的时候这里不小心调用 findMode... 导致耗时很长findModeRecursion(root.left);}if (root.val != number) {number = root.val;count = 1;} else {count++;}if (maxCount < count) {result.clear();result.add(number);maxCount = count;} else if (maxCount == count) {result.add(number);}if (root.right != null) {// 最早的时候这里不小心调用 findMode... 导致耗时很长findModeRecursion(root.right);}}
}
/*** Definition for a binary tree node.* public class TreeNode {*     int val;*     TreeNode left;*     TreeNode right;*     TreeNode() {}*     TreeNode(int val) { this.val = val; }*     TreeNode(int val, TreeNode left, TreeNode right) {*         this.val = val;*         this.left = left;*         this.right = right;*     }* }*/
// 迭代法
class Solution {private List<Integer> result = new ArrayList<>();private int maxCount = 0;private int number = 0;private int count = 0;public int[] findMode(TreeNode root) {if (root == null) {return new int[0];}Stack<TreeNode> nodes = new Stack<>();TreeNode node = root;while (node != null || !nodes.isEmpty()) {if (node != null) {nodes.push(node);node = node.left;} else {node = nodes.pop();if (node.val != number) {count = 1;} else {count++;}if (maxCount == count) {result.add(node.val);} else if (maxCount < count) {maxCount = count;result.clear();result.add(node.val);}number = node.val;node = node.right;}}int[] resultArray = new int[result.size()];for (int i = 0; i < result.size(); ++i) {resultArray[i] = result.get(i);}return resultArray;}
}

 

自己实现过程中遇到哪些困难

    刚开始使用双指针的时候, 是拿当前节点和上一个节点做比较, 如果发现不想等, 才将节点添加到 List<Integer>. 一开始以为只有这样才能知道当前字符出现的次数, 以及该频率的节点是否可以添加到结果中.

    这样做有一个问题就是, 如果所有数字都是相等的, 因为没有触发节点不想等的逻辑了.

    后来发现不行, 于是就只能在根据当前节点的值更新完 count 后, 去判断当前节点是否要添加到结果集合中. 后来发现, 如果当前 maxCount = n, 而 当前节点的 count = n, 把当前节点添加到结果集后, 尽管下一个节点和当前节点的值是一样的, 这样说明 maxCount 要更新了, 只要清空结果集重新添加一次就可以. 完美解决...

    当然, 递归方法1中, 出现了一次愚蠢的错误, 递归调用时, 调错了函数, 导致时间很长. 和随想录还有 leetcode 官方题解对了好几遍, 修改成几乎完全一样还是不对... 后来才发现调用错了函数... 所以日常没有 test case 的时候... 这样的粗心大意可是很危险的.

[LeetCode] 236. 二叉树的最近公共祖先

[LeetCode] 236. 二叉树的最近公共祖先 文章解释

[LeetCode] 236. 二叉树的最近公共祖先 视频解释

题目:

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

示例 1:

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点 5 和节点 1 的最近公共祖先是节点 3 。

示例 2:

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出:5
解释:节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。

示例 3:

输入:root = [1,2], p = 1, q = 2
输出:1

提示:

  • 树中节点数目在范围 [2, 105] 内。
  • -10^9 <= Node.val <= 10^9
  • 所有 Node.val 互不相同
  • p != q
  • pq 均存在于给定的二叉树中。

[LeetCode] 236. 二叉树的最近公共祖先

自己看到题目的第一想法

第一次:

    需要回溯! 回溯的模板我熟悉!

    首先向左侧遍历, 当找到p或者q对应的节点后, 继续往下遍历.

    于是我迷失在了节点的相互关系中.

第二次:

    递归吧, 想不明白的时候递归总是能解救迷茫的算法er.

    首先递归求左子树是否存在p或q, 再递归求右子树是否存在p或q.

    如果左子树和右子树都返回非空, 则当前节点就是公共节点.

    (提交后报错, 虽然左子树和右子树没有同时非空, 但这时候前节点是p或q中的一个, 导致返回了错误的结果)

    那再加一个条件, 如果 左子树和右子树 不同时为空, 再加一个当前节点的判断, 如果匹配p或者q中的一个节点, 则返回当前节点.

    (提交后报错, 因为这时候, 递归函数返回的节点, 可能只代表p或者q中的一个, 也可能代表p和q两者, 因此当 leftNode 和 rightNode 并非同时非空时, 不知道如何返回了)

    那就用一个数字来计数吧, 这样就知道p和q有没有都匹配上了, 但是因为我们最终的出口只有一个节点, 因此需要在主函数中接住这个节点. 同时判断匹配的数量是否为 2. 是则返回该节点, 否则返回 Null.

    至此解决问题.

第三次:

    在第二次中解决问题时, 遗漏了一个问题. 那就是题目保证了p和q是一定存在的. 这会大大的简化解题的逻辑.

看完代码随想录之后的想法

    因为 p 和 q 一定存在于二叉树中, 因此整体分两种情况:

        1. p 和 q 分别位于某个节点的左右子树中

        2. p 和 q 中有一个是公共节点

    因此, 当我们匹配到 p 或者 q 中的一个节点时, 就可以直接返回, 以该节点为根节点的子树可以不用考虑了. 因为如果该节点是公共子节点的孩子节点的话, 那另外一个就在父节点的另外一个子树中, 可以被遍历到. 或者不在该节点的父节点的另一个子树中, 而是在祖先结点的另一个子树中, 因此也可以被遍历到. 如果在其他地方找不到另外一个待匹配的节点的话, 那自然说明该节点的子节点中, 一定右另外一个可以匹配的 p 或者 q 节点.

/*** Definition for a binary tree node.* public class TreeNode {*     int val;*     TreeNode left;*     TreeNode right;*     TreeNode(int x) { val = x; }* }*/
// 自己的解法: 后序遍历, 不需要p和q同时存在(未验证)
class Solution {private TreeNode result = null;private int matchCount = 0;public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {TreeNode node = findNode(root, p, q);if (node != null && matchCount == 2) {return node;}return null;}private TreeNode findNode(TreeNode root, TreeNode p, TreeNode q) {if (root == null) {return null;}TreeNode leftNode = null;TreeNode rightNode = null;leftNode = findNode(root.left, p, q);rightNode = findNode(root.right, p, q);if (leftNode != null && rightNode != null) {return root;} else {if (root.val == q.val || root.val == p.val) {matchCount++;return root;}if (leftNode != null) {return leftNode;} else if (rightNode != null) {return rightNode;}}return null;}
}
/*** Definition for a binary tree node.* public class TreeNode {*     int val;*     TreeNode left;*     TreeNode right;*     TreeNode(int x) { val = x; }* }*/
// 后序遍历: 假设 p 和 q 一定存在
class Solution {private TreeNode result = null;private int matchCount = 0;public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {if (root == null) {return null;}TreeNode leftNode = lowestCommonAncestor(root.left, p, q);TreeNode rightNode = lowestCommonAncestor(root.right, p, q);if (leftNode != null && rightNode != null) {return root;}if (root.val == p.val || root.val == q.val) {return root;} else if (leftNode != null) {return leftNode;} else {return rightNode;}}
}

自己实现过程中遇到哪些困难

    当处理了 p 和 q 分别位于公共节点的左右子树时, p 和 q 同时位于公共节点同一侧子树的情况就无法满足. 虽然看似就那么几个判断条件, 但真正实现起来似乎怎么也绕不出来. 不过最后还是做出来了... 就是耗费的时间也真的很长. 在这一题上稍微有点沮丧.

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

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

相关文章

Flutter 中的 AnnotatedRegion 小部件:全面指南

Flutter 中的 AnnotatedRegion 小部件&#xff1a;全面指南 Flutter 的 AnnotatedRegion 是一个功能强大的小部件&#xff0c;它允许开发者在应用程序中标记特定的区域&#xff0c;并在这些区域上附加元数据。这些元数据可以被其他小部件或应用程序逻辑使用&#xff0c;以实现…

Py列表(list)

目录 正向索引&#xff1a; 反向索引&#xff1a; 嵌套列表&#xff1a; 修改列表中的值 列表常用的方法 实例 练习&#xff1a; 正向索引&#xff1a; 从0开始&#xff0c;依次递增。第一个元素的索引为0&#xff0c;第二个元素的索引为1&#xff0c;依此类推。 列表的下标…

视频太大怎么压缩变小 视频太大了怎么压缩

视频作为一种多媒体形式&#xff0c;在当今社会的重要性日益凸显&#xff0c;其应用范围广泛&#xff0c;影响力深远。 但是视频文件的大小也在不断增加&#xff0c;这给存储和传输带来了很大的困扰。那么&#xff0c;当视频文件过大时&#xff0c;我们该如何将其压缩变小呢&am…

MyBatis中常见标签的使用(动态SQL)

MyBatis 中的动态 SQL 允许你在 XML 映射文件中编写灵活的 SQL 查询语句&#xff0c;根据不同的条件动态生成不同的 SQL 语句。这样可以避免在 Java 代码中拼接 SQL 字符串&#xff0c;使得 SQL 查询更加清晰和易维护。本文章将介绍几个常见的标签并实现动态SQL 目录 一.标签…

左偏树,可合并堆

合并两个堆并维护最小或最大性质解决树上节点问题&#xff0c;从叶节点往根维护&#xff0c;每个节点看作一个堆表示到最近的叶节点的距离&#xff0c;所以每次对合并&#xff08;树高矮&#xff09;表示堆的顶点对应下标关键代码 static void dfs(int x){for(int ihead[x];i&g…

全域运营是本地生活服务的新模式吗?

最近&#xff0c;本地生活赛道又出现了一个新的说法&#xff0c;即全域运营是本地生活的下半场。事实上&#xff0c;这一论断并非空穴来风&#xff0c;而是有真凭实据。 作为多家互联网大厂重点布局的业务板块&#xff0c;本地生活的火爆程度早已有目共睹。根据多家互联网大厂…

Vue 组件功能的复用

Vue中的混入&#xff08;Mixins&#xff09;是一种复用组件逻辑的技术&#xff0c;它允许你抽取组件中的可复用功能&#xff0c;并将其作为一个独立的模块与其他组件组合。混入对象可以包含数据、计算属性、方法、生命周期钩子、侦听器等组件选项。当组件使用混入时&#xff0c…

互联网的利

在互联网没发明之前&#xff0c;人类说话要近距离的说&#xff0c;玩游戏要近距离的玩&#xff0c;十分麻烦。于是&#xff0c;互联网解决了这个问题。聊天可以在电脑上聊&#xff0c;玩游戏可以用游戏软件查找玩家来玩&#xff0c;实现了时时可聊&#xff0c;时时可玩的生活。…

nginx编译安装手把手教学

编译安装nginx的第一步需要从nginx的官网找到nginx最新的稳定版本 下面这是官方网站的资源下载地址 https://nginx.org/en/download.html选中稳定版本点击右键——选择复制链接 在终端内使用wget指令官网下载地址&#xff0c;将nginx下载 使用wget指令下载 wget https://ng…

代码模板,Cookie和Session

目录 代码模板 Cookie的基本使用 概念 Cookie的API public Cookie(String name, String value) 发送Cookie对象到客户端&#xff1a;使用response对象 创建Cookie对象并响应给浏览器 在服务器后端获取Cookie对象 Cookie[]cookiesrequset.getCookies(); Cookie的使用细…

微服务架构中Java的应用

在微服务架构中&#xff0c;Java是一种非常常用的编程语言。Java生态系统非常庞大&#xff0c;有许多框架和工具可以用来构建和管理微服务。 以下是一些在微服务架构中使用Java编写的应用程序的示例&#xff1a; Spring Boot和Spring Cloud&#xff1a;Spring Boot是一种用于快…

【InternLM实战营第二期笔记】03:“茴香豆“,搭建你的 RAG 智能助理(未完成)

文章目录 笔记-RAG课程结构为什么要用 RAG&#xff1f;定义工作原理向量数据库RAG 工作流程发展历程常见优化RAG vs 微调LLM 优化方法比较RAG的评价总结 笔记-茴香豆什么是茴香豆茴香豆实战 笔记-RAG 课程结构 为什么要用 RAG&#xff1f; 新增知识&#xff0c;尤其是高频变动…

基于51单片机简易温度计

一.硬件方案 本系统利用51单片机控制温度传感器DS18B20进行温度的实时检测并显示&#xff0c;能够实现快速测量环境温度。硬件以微控制器为核心&#xff0c;外接时钟电路、复位电路、温度测量电路、LED显示电路组成。 二.设计功能 &#xff08;1&#xff09;采用DS18B20温度…

Node.js和npm常用命令

一、Node.js简介 Node.js是一个免费、开源、跨平台的JavaScript运行时环境&#xff0c;允许开发人员创建服务器、web应用程序、命令行工具和脚本。 点击查看node.js中文官网 点击查看node.js英文官网 二、npm简介 npm(Node Package Manager)是Node.js的软件包管理器&#xff0…

使用Python编写的SIRD模型示例

代码是一个使用Python编写的SIRD模型示例,模拟传染病在人群中的传播。SIRD模型是一个经典的流行病学模型,它将人群分为四个部分:易感者(S)、感染者(I)、康复者(R)和死亡者(D)。 2. **定义SIRD模型的微分方程**: - `sird_model` 函数定义了SIRD模型的基本方程。它接受当前…

ssm150旅游网站的设计与实现+jsp

旅游网站设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本旅游网站就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞…

如何在Java中实现函数式编程?

在Java中实现函数式编程的关键是使用Lambda表达式和函数式接口。下面是一个简单的示例&#xff0c;展示了如何使用Lambda表达式和函数式接口来实现函数式编程。 首先&#xff0c;定义一个函数式接口&#xff0c;可以通过使用FunctionalInterface注解来标记该接口为函数式接口。…

解析txt文件,并以字段名为key,解析后数据为value,动态参数入库

工具方法 default ArrayList<HashMap<String,String>> txt2MapList(String[] fieldNames,File file){ArrayList<HashMap<String,String>> entityMaps new ArrayList<>();try{BufferedReader br new BufferedReader(new FileReader(file));//…

工作纪实50-Idea下载项目乱码

下载了公司的一份项目代码&#xff0c;发现是gbk格式的&#xff0c;但是我的日常习惯又是utf-8&#xff0c;下载项目以后全是乱码&#xff0c;一脸懵 借用网友的一张图&#xff0c;如果是一个一个文件这么搞&#xff0c;真的是费劲&#xff0c;好几百个文件&#xff01; 步骤…

NSS‘题目练习3

[SWPUCTF 2021 新生赛]easyupload3.0 打开题目发现要求上传.jpg文件 先上传抓包&#xff0c;尝试更改后缀 换一种形式 文件头绕过 都试过之后尝试上传.htaccess文件&#xff0c;发现上传成功 会将之后上传的文件后缀自动更名为.php 再上传.jpg文件 蚁剑连接找到flag [SWPUCTF …