当前位置: 首页 > news >正文

【算法与数据结构】235、LeetCode二叉搜索树的最近公共祖先

文章目录

  • 一、题目
  • 二、解法
  • 三、完整代码

所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解。

一、题目

在这里插入图片描述

二、解法

  思路分析:本题和这道题类似【算法与数据结构】236、LeetCode二叉树的最近公共祖先,相同的算法也能解这道题,但是没有充分利用到二叉搜索树的性质,二叉搜索树的性质为中间节点的键值大于所有左子树节点的键值,大于所有右子树的键值。因此要找到两个节点的最近祖先节点,只需要确定节点位于[p,q](或者是[q,p]大小未知,左闭右闭的区间)区间内。那么当节点键值比两个节点的键值都小时,说明公共最先节点在右子树内,遍历右子树即可,反之亦然,最终剩下的就是最近公共祖先节点
  程序如下

class Solution {
public:// 后序遍历: 左右中// 1、输入参数TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {// 2、终止条件if (root == NULL) return root;    // 如果节点相等或者是空节点返回// 3、单层递归逻辑if ((root->val > q->val && root->val > p->val)) {TreeNode* left = lowestCommonAncestor(root->left, p, q);    // 左if (left != NULL) return left;}if ((root->val < q->val && root->val < p->val)) {TreeNode* right = lowestCommonAncestor(root->right, p, q);    // 右if (right != NULL) return right;}   return root;}
};

三、完整代码

# include <iostream>
# include <vector>
# include <string>
# include <queue>
using namespace std;// 树节点定义
struct TreeNode {int val;TreeNode* left;TreeNode* right;TreeNode() : val(0), left(nullptr), right(nullptr) {}TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}TreeNode(int x, TreeNode* left, TreeNode* right) : val(x), left(left), right(right) {}
};class Solution {
public:// 后序遍历: 左右中// 1、输入参数TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {// 2、终止条件if (root == NULL) return root;    // 如果节点相等或者是空节点返回// 3、单层递归逻辑if ((root->val > q->val && root->val > p->val)) {TreeNode* left = lowestCommonAncestor(root->left, p, q);    // 左if (left != NULL) return left;}if ((root->val < q->val && root->val < p->val)) {TreeNode* right = lowestCommonAncestor(root->right, p, q);    // 右if (right != NULL) return right;}   return root;}
};// 前序遍历迭代法创建二叉树,每次迭代将容器首元素弹出(弹出代码还可以再优化)
void Tree_Generator(vector<string>& t, TreeNode*& node) {if (!t.size() || t[0] == "NULL") return;    // 退出条件else {node = new TreeNode(stoi(t[0].c_str()));    // 中if (t.size()) {t.assign(t.begin() + 1, t.end());Tree_Generator(t, node->left);              // 左}if (t.size()) {t.assign(t.begin() + 1, t.end());Tree_Generator(t, node->right);             // 右}}
}template<typename T>
void my_print(T& v, const string msg)
{cout << msg << endl;for (class T::iterator it = v.begin(); it != v.end(); it++) {cout << *it << ' ';}cout << endl;
}template<class T1, class T2>
void my_print2(T1& v, const string str) {cout << str << endl;for (class T1::iterator vit = v.begin(); vit < v.end(); ++vit) {for (class T2::iterator it = (*vit).begin(); it < (*vit).end(); ++it) {cout << *it << ' ';}cout << endl;}
}// 层序遍历
vector<vector<int>> levelOrder(TreeNode* root) {queue<TreeNode*> que;if (root != NULL) que.push(root);vector<vector<int>> result;while (!que.empty()) {int size = que.size();  // size必须固定, que.size()是不断变化的vector<int> vec;for (int i = 0; i < size; ++i) {TreeNode* node = que.front();que.pop();vec.push_back(node->val);if (node->left) que.push(node->left);if (node->right) que.push(node->right);}result.push_back(vec);}return result;
}// 前序遍历,找二叉树中指定的键值
TreeNode* traversal_preOrder(TreeNode* cur, int val) {if (cur == NULL) return NULL;if (cur->val == val) return cur;        // 中if (traversal_preOrder(cur->left, val) != NULL) return traversal_preOrder(cur->left, val);        // 左   if (traversal_preOrder(cur->right, val) != NULL) return traversal_preOrder(cur->right, val);     // 右  return NULL;
}int main()
{// 构建二叉树vector<string> t = { "6", "2", "0", "NULL", "NULL", "4", "3", "NULL", "NULL", "5", "NULL", "NULL", "8", "7", "NULL", "NULL", "9", "NULL", "NULL" };   // 前序遍历my_print(t, "目标树");TreeNode* root = new TreeNode();Tree_Generator(t, root);vector<vector<int>> tree = levelOrder(root);my_print2<vector<vector<int>>, vector<int>>(tree, "目标树:");// 构建p, q节点int p = 2, q = 8;TreeNode* P_node = traversal_preOrder(root, p);TreeNode* Q_node = traversal_preOrder(root, q);// 找最近公共祖先节点Solution s;TreeNode* result = s.lowestCommonAncestor(root, P_node, Q_node);cout << "节点 " << P_node->val << " 和节点 " << Q_node->val << " 的最近公共祖先节点为 " << result->val << endl;system("pause");return 0;
}

end

相关文章:

【算法与数据结构】235、LeetCode二叉搜索树的最近公共祖先

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;本题和这道题类似【算法与数据结构】236、LeetCode二叉树的最近公共祖先&#xff0c;相同的算法也能解…...

bboss 流批一体化框架 与 数据采集 ETL

数据采集 ETL 与 流批一体化框架 特性&#xff1a; 高效、稳定、快速、安全 bboss 是一个基于开源协议 Apache License 发布的开源项目&#xff0c;主要由以下三部分构成&#xff1a; Elasticsearch Highlevel Java Restclient &#xff0c; 一个高性能高兼容性的Elasticsea…...

JVM详细教程

JVM 前言 还在完善中先发布 JVM虚拟机厂家多钟多样&#xff0c;具体实现细节可能不一样&#xff0c;这里主要讲的是虚拟机的规范&#xff0c;以下内容融合了各个平台发布的内容和周志明老师的《深入理解java虚拟机》 JVM概述 如何理解jvm跨平台&#xff1f; 编译成汇编代码…...

Smartbi吴华夫:后疫情时代,BI发展趋势的观察与应对

沿着旧地图找不到新大陆&#xff0c;“基于指标体系的可视化分析和增强分析”成为BI发展新阶段。Smartbi V11系列新品与时俱进&#xff0c;以指标为核心&#xff0c;同时融合BI应用&#xff0c;赋能管理者和业务&#xff0c;成为引领数字化运营的新航标&#xff01; ——思迈特…...

软件设计模式系列之三———工厂方法模式

1 模式的定义 工厂方法模式是一种常见的设计模式&#xff0c;属于创建型设计模式之一&#xff0c;它在软件工程中用于对象的创建。该模式的主要思想是将对象的创建过程抽象化&#xff0c;将具体对象的实例化延迟到子类中完成&#xff0c;以便在不同情况下可以创建不同类型的对…...

pytorch 多卡分布式训练 调用all_gather_object 出现阻塞等待死锁的问题

pytorch 多卡分布式训练 torch._C._distributed_c10d中的函数all_gather_object 出现阻塞等待死锁的问题 解决办法就是 在进程通信之前调用torch.cuda.set_device(local_rank) For NCCL-based processed groups, internal tensor representations of objects must be moved …...

SpringMvc增删改查

SpringMvc增删改查 一、前期准备二、逆向生成增删改查2.2.aspect切面层2.3.Mybatis generator逆向生成2.4.根据生成代码编写Biz层与实现类 三、controller层代码编写四、前台代码与分页代码五、案例测试 一、前期准备 1.2.导入pom.xml依赖 <?xml version"1.0" …...

【计算机网络】网络编程接口 Socket API 解读(5)

Socket 是网络协议栈暴露给编程人员的 API&#xff0c;相比复杂的计算机网络协议&#xff0c;API 对关键操作和配置数据进行了抽象&#xff0c;简化了程序编程。 本文讲述的 socket 内容源自 Linux man。本文主要对各 API 进行详细介绍&#xff0c;从而更好的理解 socket 编程。…...

手动实现一个bind函数!

原文地址&#xff1a;手动实现一个bind函数&#xff01; - 知乎 1.bind函数用法 bind()方法用于创建一个新的函数&#xff0c;这个新函数接收的第一个参数代表的就是this&#xff0c;利用bind()函数我就就可以任意改变函数内部的this指向了。 官网的解释&#xff1a; bind()…...

数据结构-时间复杂度/空间复杂度

Hello&#xff0c;好久没有更新了哦&#xff0c;已经开始学习数据结构了&#xff0c;这篇文章呢就是对刚学数据结构所接触到的时间复杂度进行一个分享哦&#xff0c;如果有错误之处&#xff0c;大家记得拍拍我哦~ 既然要讨论时间/空间复杂度&#xff0c;那我们就得知道时间/空…...

英语写作中“展示”、“表明”demonstrate、show、indicate、illustrate的用法

一、demonstrate、show、indicate在论文写作中主要用法是&#xff1a;demonstrate/show/indicate 从句&#xff1a; Sb./Sth. demonstrates/shows/indicates that ……从句中一般表达事实、观点和结论等。 例句&#xff1a; The authors demonstrated/showed/indicated that…...

Redis的java客户端

在Redis官网中提供了各种语言的客户端&#xff0c;地址&#xff1a;https://redis.io/resources/clients/ redis的java客户端 https://redis.io/resources/clients/#java 1.jedis使用 引入依赖 <dependency><groupId>redis.clients</groupId><artifac…...

Android环境配置笔记

文章目录 一、各环境文档二、参考 一、各环境文档 Gradle官方的兼容性文档&#xff1a;Java Compatibility 更新日期&#xff1a;2023.9.12 Android Gradle插件版本&#xff1a;Android Gradle Plugin 二、参考 参考文章&#xff1a;Android问题记录...

element-table 行的拖拽更改顺序(无需下载sortableJs

样例展示&#xff1a;vueelement 通过阅读element文档我们发现element并不提供拖拽相关的api 本博客通过element提供的行类名 注册函数 实现行与行的拖拽 1.设置el-table 的行样式类名 这里是用的是 function <el-table:data"outputData":row-class-name&qu…...

Docker部署jenkins

目录 一、jenkins原理二、Docker部署jenkins1.下载jenkins镜像文件2.查看下载的jenkins镜像3.创建Jenkins挂载目录并授权权限4.创建并启动Jenkins容器5.查看jenkins是否启动成功6.查看docker容器日志7.配置镜像加速8.访问Jenkins页面&#xff0c;输入ip地址加上9000端口9.获取管…...

从0到1学会Git(第三部分):Git的远程仓库链接与操作

写在前面:前面两篇文章我们已经学会了git如何在本地进行使用&#xff0c;这篇文章将讲解如何将本地的git仓库和云端的远程仓库链接起来并使用 为什么要使用远程仓库:因为我们需要拷贝我们的代码给别人以及进行协同开发&#xff0c;就需要有一个云端仓库进行代码的存储和同步&a…...

虚拟机Ubuntu操作系统常用终端命令(1)(详细解释+详细演示)

虚拟机Ubuntu操作系统常用终端命令 本篇讲述了Ubuntu操作系统常用的三个功能&#xff0c;即归档&#xff0c;软链接和用户管理方面的相关知识。希望能够得到大家的支持。 文章目录 虚拟机Ubuntu操作系统常用终端命令二、使用步骤1.归档1.1创建档案包1.2还原档案包1.3归档并压缩…...

redis实战-redis实现异步秒杀优化

秒杀优化-异步秒杀思路 未优化的思路 当用户发起请求&#xff0c;此时会请求nginx&#xff0c;nginx会访问到tomcat&#xff0c;而tomcat中的程序&#xff0c;会进行串行操作&#xff0c;分成如下几个步骤 1、查询优惠卷 2、判断秒杀库存是否足够 3、查询订单 4、校验是否是一…...

Python爬虫-IP隐藏技术与代理爬取

前言 在进行爬虫程序开发和运行时&#xff0c;常常会遇到目标网站的反爬虫机制&#xff0c;最常见的就是IP封禁&#xff0c;这时需要使用IP隐藏技术和代理爬取。 一、IP隐藏技术 IP隐藏技术&#xff0c;即伪装IP地址&#xff0c;使得爬虫请求的IP地址不被目标网站识别为爬虫。…...

二刷力扣--链表

链表 链表类型&#xff1a; 单链表&#xff08;可以访问后面的一个节点&#xff09; 双链表&#xff08;可以访问前后节点&#xff09; 循环链表&#xff08;最后一个节点指向首节点&#xff09; 在Python中定义单链表节点&#xff1a; class ListNode:def __init__(self, v…...

解密智能工具:3步实现Windows高效安装Android应用

解密智能工具&#xff1a;3步实现Windows高效安装Android应用 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 在数字生活日益融合的今天&#xff0c;你是否曾为Windows…...

基于Next.js 15与React 19构建现代化个人作品集:技术选型与工程实践

1. 项目概述&#xff1a;为什么选择 Next.js 15 构建现代个人作品集 作为一名在前后端领域摸爬滚打了十多年的开发者&#xff0c;我见过也亲手搭建过无数种个人作品集网站。从早期的纯静态 HTML/CSS&#xff0c;到 jQuery 时代&#xff0c;再到 React/Vue 等框架的兴起&#x…...

ECA:编辑器无关的AI编程伴侣,统一配置多模型与编辑器

1. 项目概述&#xff1a;一个编辑器无关的AI编程伴侣如果你和我一样&#xff0c;每天大部分时间都泡在编辑器里&#xff0c;那你肯定也经历过这种场景&#xff1a;面对一段复杂的业务逻辑&#xff0c;或者一个陌生的API&#xff0c;你希望有个“懂行”的伙伴能立刻给你解释、重…...

边缘计算中的机器学习能效优化与混合架构实践

1. 边缘计算中的机器学习能效革命在智能手表、健康监测设备等穿戴式设备中&#xff0c;实时运行机器学习模型一直是个棘手的问题。传统方案要么耗电太快导致续航崩溃&#xff0c;要么精度太低失去实用价值。我们团队最近实验的一组数据很能说明问题&#xff1a;在常见的运动识别…...

观察taotoken在ubuntu高峰期调用时的稳定性与自动路由效果

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 观察 Taotoken 在 Ubuntu 高峰期调用时的稳定性与自动路由效果 1. 背景与测试环境 在日常的开发与调试工作中&#xff0c;我们经常…...

Docker 的了解和使用

1. 虚拟化全虚拟化&#xff1a;虚拟机的操作系统可以和宿主机的操作系统完全不同。os层虚拟化&#xff1a;操作内核相同&#xff0c;软件虚拟化。2. docker安装 Docker容器本质上是Linux容器&#xff0c;它需要Linux内核环境才能运行。在Windows上直接运行Docker&#xff0c;需…...

Anthropic新模型Mythos号称擅查漏洞,扫描curl代码却仅确认1个低危问题

Mythos高调亮相&#xff0c;扫描结果却令人意外 近期&#xff0c;Anthropic推出的AI安全分析模型Mythos引发广泛关注&#xff0c;该公司宣称其在发现源代码安全漏洞方面表现出色&#xff0c;甚至因此暂缓公开发布。然而&#xff0c;当Mythos扫描全球最广泛使用的开源命令行HTTP…...

基于RAG与向量数据库的智能知识库构建实战指南

1. 项目概述&#xff1a;一个开源的深度知识库构建与问答引擎最近在折腾一个挺有意思的开源项目&#xff0c;叫deepwiki-open。简单来说&#xff0c;它就是一个帮你把一堆文档&#xff08;比如公司内部Wiki、产品手册、技术文档&#xff09;变成一个能“听懂人话”并“对答如流…...

Simulink仿真避坑指南:PWM控制48V直流电机时,轻载和重载下的参数设置与波形分析(附2018a源文件)

Simulink仿真避坑指南&#xff1a;PWM控制48V直流电机时&#xff0c;轻载和重载下的参数设置与波形分析 在工程实践中&#xff0c;直流电机的仿真建模是验证控制算法和预测系统性能的关键环节。特别是当面对不同负载条件时&#xff0c;如何准确设置电机参数并解读仿真波形&…...

【AI面试临阵磨枪-54】如何监控 AI 系统:成功率、延迟、Token 消耗、幻觉率、调用量

一、 面试题目面试官提问&#xff1a; “在大规模 Agent 系统中&#xff0c;你是如何建立监控体系的&#xff1f;请针对 成功率、延迟、Token 消耗、幻觉率、调用量 这五个核心指标&#xff0c;详细谈谈你的采集、分析与预警方案。”二、 知识储备1. 核心背景&#xff1a;AI 监…...