24暑假算法刷题 | Day18 | LeetCode 530. 二叉搜索树的最小绝对差,501. 二叉搜索树中的众数,236. 二叉树的最近公共祖先

目录

  • 530. 二叉搜索树的最小绝对差
    • 题目描述
    • 题解
  • 501. 二叉搜索树中的众数
    • 题目描述
    • 题解
  • 236. 二叉树的最近公共祖先
    • 题目描述
    • 题解


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 <= 105

题解

暴力解法把所有节点两两相减、求绝对值最小的差即可,时间复杂度为 O ( n 2 ) O(n^2) O(n2)

我们可以利用二叉搜索树的一个重要性质来优化算法:

  • 二叉搜索树的中序遍历结果是一个从小到大的有序数列

此处默认节点左子树中各节点值小于节点、右子树中各节点值大于节点,则上面的性质是显然的。

也就是说,如果我们先获得中序遍历结果,再从头到尾依次两两相减,只需要遍历一次就可以得出最小绝对差。

由于中序遍历结果是递增序列,最小的任意两数之差肯定出现在相邻的两数之间;且后一个数大于前一个数,所以总让后一个数减去前一个数,所得结果必为正数,不必再求绝对值。

显然,这一算法可以直接在中序遍历的过程中运行,C++代码如下:

int res = INT_MAX;
TreeNode *pre; // 暂存中序遍历时前一个节点的指针void traversal(TreeNode *root)
{if (root->left)traversal(root->left); // 左if (pre)res = min(res, root->val - pre->val); // 中pre = root;                               // 更新前指针if (root->right)traversal(root->right); // 右
}int getMinimumDifference(TreeNode *root)
{traversal(root);return res;
}

501. 二叉搜索树中的众数

点此跳转题目链接

题目描述

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

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

假定 BST 满足如下定义:

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

示例 1:

在这里插入图片描述

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

示例 2:

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

提示:

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

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

题解

既然是找众数,那么将二叉树遍历一遍、记录每个数出现的频率,是必不可少的了。常规思路应该是:

  • 遍历该树,同时记录节点值的出现频率

  • 找到最大的出现频率

  • 将出现频率最大的数加入结果集

    ⚠️ 注意题目说了,众数可能不止一个

当然,后两步可以合并:当发现更大的频率的时候,先将现有结果集清空,再加入新的最高频数字。这种方法的C++代码如下:

class Solution
{
public:unordered_map<int, int> freqMap; // 用一个哈希表记录每个数值出现的频率int maxShowTime = -1;// 中序遍历void traversal(TreeNode *cur){if (cur->left)traversal(cur->left); // 左freqMap[cur->val]++;      // 中if (cur->right)traversal(cur->right); // 右}vector<int> findMode(TreeNode *root){traversal(root);vector<int> res;for (const auto &pair : freqMap){if (pair.second > maxShowTime){maxShowTime = pair.second;res.clear(); // 出现更高频的元素,将原来的结果集清空res.push_back(pair.first);}else if (pair.second == maxShowTime)res.push_back(pair.first); // 众数可能不止一个}return res;}
};

不过,上述方法显然对任意树是通用的,意味着我们并没有利用到二叉搜索树的独特性质。同时,题目进阶要求也说了,可以不使用额外空间解决此题(上面的算法有个额外的哈希表空间开销)。

即是二叉搜索树,又要遍历之,自然联想到性质:

  • 二叉搜索树的中序遍历结果是一个从小到大的有序数列

所以,我们可以采用中序遍历的方法:

  • 如果当前节点值和上一个节点值相同,则当前频率加1;否则,说明遍历到一个新数值的节点,将当前频率重置为1
  • 如果当前频率等于最大频率,则将当前节点值加入结果集
  • 如果当前频率大于最大频率,则更新最大频率,清空原来结果集,将当前节点值接入结果集

这样,就避免了额外的空间开销:

class Solution
{
public:int maxShowTime = -1;int curShowTime = 0;TreeNode *pre = nullptr; // 中序遍历序列中,当前节点的前一个节点vector<int> res;// 中序遍历void traversal(TreeNode *cur){// 左if (cur->left)traversal(cur->left); // 中if (!pre)curShowTime = 1; // 第一个节点else if (cur->val == pre->val)curShowTime++; // 相同的节点值elsecurShowTime = 1; // 新的节点值pre = cur; // 更新前节点指针if (curShowTime == maxShowTime)res.push_back(cur->val);if (curShowTime > maxShowTime) {maxShowTime = curShowTime; // 更新最大出现频率res.clear();               // 清除之前的结果res.push_back(cur->val);}// 右if (cur->right)traversal(cur->right);}vector<int> findMode(TreeNode *root){traversal(root);return res;}
};

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] 内。
  • -109 <= Node.val <= 109
  • 所有 Node.val 互不相同
  • p != q
  • pq 均存在于给定的二叉树中。

题解

根据题目描述,可以发现,符合直觉的思路是自底向上地查找——而这与后序遍历的遍历顺序相符。所以,我们考虑基于后序遍历,递归地返回 pq 的最近公共祖先。

用递归,首先考虑递归出口。我们想要返回的总是一个 p 和/或 q 的祖宗节点,所以以当前节点 root 的左右子树中必须有 p 和/或 q (自然,也有其祖宗节点),否则返回空节点:

if (!left && !right)return nullptr;

按照这种思路,节点不为空即说明该节点是 pq 或者它们之一/公共的祖宗节点

其余情况,即 root 的左右子树不都为空,说明它们之中有 p 和/或 q 及其祖宗节点:

1️⃣ 先看看最简单的情况:类似上面的示例1,当前节点 root 的左孩子 leftright 恰好就是 pq (对应关系无所谓),则 root 就是它们的最近公共祖先,此时返回 root 即可:

if (left && right)return root;

2️⃣ 如果当前节点是 pq ,也直接返回当前节点即可:题目说了 一个节点也可以是它自己的祖先

if (root == p || root == q)return root;

3️⃣ 如果 leftright 之间有且仅有一个不为空,则返回不为空的那个节点——该节点是 pq 或它们之一/公共的祖先:

相当于上面示例2中的节点 2

if (left && !right)return left;
if (!left && right)return right;

整体C++代码如下:

TreeNode *lowestCommonAncestor(TreeNode *root, TreeNode *p, TreeNode *q)
{// 基于后序遍历if (!root)return nullptr;TreeNode *left = lowestCommonAncestor(root->left, p, q);   // 左TreeNode *right = lowestCommonAncestor(root->right, p, q); // 右// 中// 当前节点为p, q之一if (root == p || root == q)return root;// 否则,看左右孩子节点的情况else if (left && right)return root;else if (left && !right)return left;else if (!left && right)return right;else // 左右都为空return nullptr;
}

该算法更详细的讲解参见 代码随想录的本题题解 。

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

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

相关文章

Python 更换 pip 源详细指南

目录 前言pip 国内源临时换源方法一&#xff1a;添加参数方法二&#xff1a;设置环境变量 永久换源方法三&#xff1a;修改配置方法四&#xff1a;pip 命令修改 总结 前言 在我们使用 Python 3 时&#xff0c;pip 是一个不可或缺的工具&#xff0c;它用于安装和管理第三方库。…

在虚拟机 CentOS7 环境下安装 MySQL5.7 数据库

配置目标 在虚拟机的 Linux CentOS7 环境下安装 MySQL5.7 版数据库&#xff0c;并能从宿主机 Windows 系统连接该数据库&#xff08;默认端口&#xff1a;3306&#xff09;。 1. 准备工作 WMware 虚拟机&#xff1a;VMware Workstation 16 ProCentOS7 镜像&#xff1a;CentO…

ubuntu 上安装软件

1.ubuntu 上安装火狐 在Ubuntu上安装Mozilla Firefox&#xff08;火狐浏览器&#xff09;通常很简单&#xff0c;你可以通过Ubuntu的软件包管理器来完成安装。以下是安装步骤&#xff1a; 打开终端&#xff08;Terminal&#xff09;。 更新你的软件包列表&#xff0c;以确保你…

基于密钥的身份验证(Linux-Linux)

A主机&#xff1a; 1、生成密钥对 [rootservera ~]# ssh-keygen查看公钥 注&#xff1a;id_rsa为私钥&#xff08;证书&#xff09;&#xff0c;id_rsa.pub为公钥 2、注册公钥到服务器 [rootservera ~]# ssh-copy-id root172.25.250.106 查看.ssh 3、使用密钥连接服务器 #…

域名解析中断

在当今数字化的时代&#xff0c;网络已经成为我们生活和工作中不可或缺的一部分。然而&#xff0c;当域名解析中断时&#xff0c;整个网络世界仿佛瞬间陷入了混乱&#xff0c;给个人和企业带来诸多不便和损失。 域名解析&#xff0c;简单来说&#xff0c;就是将我们在浏览器中…

【yolov8】3、yolov8 环境安装 【GPU版】

pycharm下载安装 yolov8 环境安装 【GPU版】 1、要求1.1 什么是 CUDA 和 CUDNN1.2 查看cuda版本的3种方法&#xff08;版本在10.2以上的可以忽略本章节&#xff09;&#xff1a;1.3 没有找到NIVDIA图标&#xff0c;确认是否有英伟达显卡 2、pycharm下载安装进入官网 3、yolov8…

【Android】视图与常用控件总结

文章目录 一、视图基础1.1 设置视图的宽高1.2 设置视图的间距1.3 设置视图的对齐方式1.4 总结 二、控件2.1 TextView2.1.1 设置宽高2.1.2 设置内容2.1.3 设置大小2.1.4 设置颜色 2.2 Button2.3 EditText2.4 ImageView2.5 ProgressBar2.6 AlertDialog2.7 ProgressDialog 本文主要…

JAVASE进阶day14(网络编程续TCP,日志)

TCP 三次握手 四次挥手 package com.lu.day14.tcp;import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket;public class Client {public static void main(String[] args) {try(Socket socket new Socket("192.…

哈默纳科HarmonicDrive减速机组装注意事项

在机械行业中&#xff0c;精密传动设备HarmonicDrive减速机对于维持机械运作的稳定性和高效性起着至关重要的作用。然而在减速机的组装过程中&#xff0c;任何一个细微的错误都可能导致其运转时出现振动、异响等不良现象&#xff0c;严重时甚至可能影响整机的性能。因此&#x…

【开源库】libodb库编译及使用

前言 本文介绍windows平台下libodb库的编译及使用。 文末提供libodb-2.4.0编译好的msvc2019_64版本&#xff0c;可直接跳转自取 ODB库学习相关 【开源库学习】libodb库学习&#xff08;一&#xff09; 【开源库学习】libodb库学习&#xff08;二&#xff09; 【开源库学习】…

30种图像动画特效算法(C#多线程版) - 好文要转

最近想做一个屏幕保护软件&#xff0c;需要图片切换效果&#xff0c;于是就找到这个博文&#xff0c;强烈推荐&#xff1a; https://blog.51cto.com/mengliao/473169 其中的源码包在此下载&#xff1a;https://download.csdn.net/download/lzhdim/89532212 效果如下&#xff1a…

Linux 中停止 Docker 服务报 warning 导致无法彻底停止问题如何解决?

目录 问题 systemd Docker Service 和 Socket 警告的原因 解决方法 问题 使用如下命令停止 Docker # systemctl stop docker 执行后报的时候报了一个 warning&#xff0c;如下 Warning: Stopping docker.service, but it can still be activated by:docker.socket 这时…

Unity | AssetBundle

1 定义 Unity中的一种特殊资源包格式&#xff0c;用于存储和分发游戏资源。这些资源可以包括模型、纹理、音频文件、预制体、场景等。 AssetBundle允许开发者在游戏运行时动态加载和卸载资源&#xff0c;从而实现灵活的资源管理。 2 使用场景 1、资源管理 有效管理游戏中的资…

Pycharm 安装与使用

PyCharm的安装与使用 一、什么是PyCharm PyCharm是由JetBrains开发的专业Python集成开发环境&#xff08;IDE&#xff09;&#xff0c;提供智能代码补全、语法高亮和代码导航等编辑功能。它具有强大的调试工具和内置版本控制系统支持&#xff0c;方便代码管理和协作。PyCharm…

《小程序02:云开发之增删改查》

一、前置操作 // 一定要用这个符号包含里面的${}才会生效 wx.showToast({title: 获取数据成功&#xff1a;${colorLista}, })1.1&#xff1a;初始化介绍 **1、获取数据库引用&#xff1a;**在开始使用数据库 API 进行增删改查操作之前&#xff0c;需要先获取数据库的引用 cons…

ABAP:创建/修改成本中心

学习内容描述&#xff1a;利用SAP的标准BAPI创建/修改成本中心 业务参考文档&#xff1a;【SAP-CO】成本中心的创建、变更与删除_sap ks01 函数-CSDN博客 重点知识&#xff1a;标准BAPI的调用 1、创建&#xff1a;BAPI_COSTCENTER_CREATEMULTIPLE DATA: lt_costcenterlist TY…

<数据集>安全帽佩戴识别数据集<目标检测>

数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;3912张 图片分辨率&#xff1a;640640 标注数量(xml文件个数)&#xff1a;3912 标注数量(txt文件个数)&#xff1a;3912 标注类别数&#xff1a;2 标注类别名称&#xff1a;[no-helmet, helmet] 序号类别名称图片…

在麒麟服务器 V10 SP3 上将 Redis 设置为开机自启

要在麒麟服务器 V10 SP3 上将 Redis 设置为开机自启&#xff0c;可以使用 systemd 来管理 Redis 服务。以下是详细步骤&#xff1a; 1、创建一个 systemd 服务单元文件&#xff1a; 首先&#xff0c;创建一个新的服务单元文件&#xff0c;例如 redis.service。 sudo nano /e…

刷题Day59|prim算法与kruskal算法:53. 寻宝

参考&#xff1a;代码随想录&#xff08;http://www.programmercarl.com&#xff09; 53. 寻宝 53. 寻宝&#xff08;第七期模拟笔试&#xff09; (kamacoder.com) prim算法思路&#xff1a; 第一步&#xff0c;选距离生成树最近的节点第二步&#xff0c;最近的节点加入生成…

机器学习——降维算法PCA和SVD(sklearn)

目录 一、基础认识 1. 介绍 2. 认识 “ 维度 ” &#xff08;1&#xff09;数组和Series &#xff08;2&#xff09;DataFrame 表 &#xff08;3&#xff09;图像 3. 降维思想 4. 降维步骤 二、降维算法&#xff08;PCA&#xff09; 1. PCA实现 &#xff08;1&#…