剑指Offer68-I.二叉搜索树的最近公共祖先 C++

1、题目描述

  • 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
  • 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
  • 例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]
    在这里插入图片描述
    示例 1:
    输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
    输出: 6
    解释: 节点 2 和节点 8 的最近公共祖先是 6。
    示例 2:
    输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
    输出: 2
    解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。

2、VS2019上运行

方法一:两次遍历、递归的方法

#include <iostream>
#include <vector>

using namespace std;

// Definition for a binary tree node
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;

    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

class Solution {
public:
    // 获取从根节点到目标节点的路径
    vector<TreeNode*> getPath(TreeNode* root, TreeNode* target) {
        vector<TreeNode*> path;
        TreeNode* node = root;
        while (node != target) {
            path.push_back(node);//遍历到一个节点时,将该节点加入到路径path中
            if (target->val < node->val) {//利用二叉搜索树的特点:左子树小于节点
                node = node->left;
            }
            else {
                node = node->right;
            }
        }
        path.push_back(node);//把最后一个target的值加入到path路径中
        return path;
    }

    // 找到最近公共祖先
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        vector<TreeNode*> path_p = getPath(root, p);
        vector<TreeNode*> path_q = getPath(root, q);
        TreeNode* ancestor = nullptr;///用于保存最低公共祖先节点
        for (int i = 0; i < path_p.size() && i < path_q.size(); ++i) {
            if (path_p[i] == path_q[i]) {
                ancestor = path_p[i];
            }
            else {
                break;//如果有不相等的节点出现,那么这些节点之前的节点就是最低公共祖先节点的祖先。
            }
        }
        return ancestor;
    }
};

int main() {
    // Create the binary search tree
    TreeNode* root = new TreeNode(6);
    root->left = new TreeNode(2);
    root->right = new TreeNode(8);
    root->left->left = new TreeNode(0);
    root->left->right = new TreeNode(4);
    root->right->left = new TreeNode(7);
    root->right->right = new TreeNode(9);
    root->left->right->left = new TreeNode(3);
    root->left->right->right = new TreeNode(5);

    Solution solution;

    // Find the lowest common ancestor of nodes 2 and 4
    TreeNode* p = root->left;
    TreeNode* q = root->left->right;
    TreeNode* lca = solution.lowestCommonAncestor(root, p, q);

    cout << "Lowest Common Ancestor: " << lca->val << endl; // Output: 2

    // Remember to free the memory
    // ...

    return 0;
}

Lowest Common Ancestor: 2

3、解题思路

  • 使用二叉搜索树的特性以及节点路径的比较来找到两个给定节点的最近公共祖先。
  • 首先,我们定义了一个辅助函数 getPath,用于获取从根节点到目标节点的路径。在该函数中,我们从根节点开始遍历树,将经过的节点加入到路径中,直到遍历到目标节点为止。这个函数利用了二叉搜索树的特点,当目标节点的值小于当前节点的值时,我们向左子树移动;当目标节点的值大于当前节点的值时,我们向右子树移动。
  • 接下来,我们定义了主函数 lowestCommonAncestor,用于找到给定两个节点的最近公共祖先。首先,我们分别调用 getPath 函数得到两个节点的路径。然后,我们从路径的开头开始,逐一比较路径中的节点,如果当前节点相同,那么这个节点就是最低公共祖先。一旦遇到路径中有节点不同的情况,就说明之前的节点是最低公共祖先的祖先节点,因此我们可以直接返回最低公共祖先。
  • 总结起来,这个算法的思路是通过比较节点路径来找到最近公共祖先。首先获取从根节点到两个目标节点的路径,然后逐一比较路径中的节点,找到最低公共祖先节点。这个算法的时间复杂度是 O(N),其中 N 是二叉搜索树中的节点数。

4、 path.push_back(node);

第一个:

  • path.push_back(node)这行代码是在getPath函数中,在每次遍历到一个节点时,将该节点加入到路径path中。
  • 目的是为了将遍历过的节点按顺序保存下来,构成从根节点到目标节点的路径。通过将每个节点添加到path中,最后得到的path向量就是从根节点到目标节点的完整路径。
  • 在遍历完成后,path向量中的最后一个元素就是目标节点本身,因为在遍历过程中,当节点等于目标节点时,也会将目标节点加入到path中

第二个:

  • 循环结束后,我们已经找到了目标节点target,并将其添加到路径path中。但是,最后一个节点target还未添加到路径path中。
  • 在当前的代码实现中,最后一个节点将是target节点,但是由于循环退出的条件是node != target,所以最后一次循环中node被更新为target,因此循环结束时node已经指向了目标节点。
  • 为了将目标节点添加到路径path中,我们需要在循环结束后将其再次添加到path中,以保证路径的完整性。所以,代码中最后一行的path.push_back(node)的作用就是将目标节点target添加到路径path的末尾。

5、二叉搜索树

  • 二叉搜索树(Binary Search Tree,BST)是一种特殊类型的二叉树,它满足以下性质:
  • 1、每个节点都有一个值,且节点的值唯一。
  • 2、对于任意节点,其左子树中的所有节点的值都小于节点的值。
  • 3、对于任意节点,其右子树中的所有节点的值都大于节点的值。
  • 4、左子树和右子树也分别是二叉搜索树。

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

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

相关文章

uni——月份选择(横向滑动tab,横向滚动选择日期)

案例展示 案例代码 已封装成组件使用 <template><view><view class"tabBox"><scroll-view scroll-x"true" :scroll-left"scrollLeft" :scroll-with-animation"true"><view class"box"><…

STM32--EXTI外部中断

前文回顾---STM32--GPIO 相关回顾--有关中断系统简介 目录 STM32中断 NVIC EXTI外部中断 AFIO EXTI框图 旋转编码器简介 对射式红外传感器工程 代码&#xff1a; 旋转编码器工程 代码&#xff1a; STM32中断 先说一下基本原理&#xff1a; 1.中断请求发生&#xff1a…

Zabbix自动注册服务器及部署代理服务器

文章目录 一.zabbix自动注册1.什么是自动注册2.环境准备3.zabbix客户端配置4.在 Web 页面配置自动注册5.验证自动注册 二.部署 zabbix 代理服务器1.分布式监控的作用&#xff1a;2.环境部署3.代理服务器配置4.客户端配置5.web页面配置5.1 删除原来配置5.2 添加代理5.3 创建主机…

周末在家值班,解决几个月前遗忘的Bug

问题&#xff1a; 周末被迫在家值班&#xff0c;无聊之际打开尘封已久的Bug清单&#xff0c;发现有Bug拖了几个月还没解决… 场景是这样子的&#xff0c;有个功能是拿Redis缓存热点数据进行展示&#xff0c;暂且称它为功能A&#xff0c;有个另外的功能B&#xff0c;它会去更新缓…

day3 STM32 GPIO口介绍

GPIO接口简介 通用输入输出接口GPIO是嵌入式系统、单片机开发过程最常用的接口&#xff0c;用户可以通过编程灵活的对接口进行控制&#xff0c;实现对电路板上LED、数码管、按键等常用设备控制驱动&#xff0c;也可以作为串口的数据收发管脚&#xff0c;或AD的接口等复用功能使…

家政服务平台|家政上门服务系统打开时代新渠道

在快节奏的现代社会&#xff0c;工作和家庭的双重压力常常使人们备受折磨。为了缓解这种压力&#xff0c;我们公司推出了一款创新的家政上门服务系统&#xff0c;旨在为您提供便捷、高效的生活服务。通过结合先进技术和人性化服务&#xff0c;我们致力于改善您的生活品质&#…

JPA实现存储实体类型信息

本文已收录于专栏 《Java》 目录 背景介绍概念说明DiscriminatorValue 注解&#xff1a;DiscriminatorColumn 注解&#xff1a;Inheritance(strategy InheritanceType.SINGLE_TABLE) 注解&#xff1a; 实现方式父类子类执行效果 总结提升 背景介绍 在我们项目开发的过程中经常…

CMake:检测python模块和包

CMake:检测python模块和包 导言项目结构CMakeLists.txt相关源码 导言 上一篇&#xff0c;我们基本了解了如何去检测python的解释器和python库。通常&#xff0c;代码是依赖于特定的python模块&#xff0c;无论是python工具、嵌入python的程序&#xff0c;还是扩展python的库。…

法律监督大数据平台有什么作用?

大数据赋能时代法律监督&#xff0c;构建法律行业领域大数据监督模型。法律监督大数据研判系统助力检察机关以社会公正为核心价值追求&#xff0c;对执法不严、司法不公“零容忍”&#xff0c;强化对诉讼活动的法律监督&#xff0c;坚决维护法律尊严&#xff0c;坚决捍卫公平正…

创建Springboot+vue3项目

项目概述创建springboot项目加入mybatis-plus支持1.加入依赖代码2.创建数据库实例3.yml文件的配置4.编写测试代码5.测试结果 创建vue项目报错错误一错误二错误三 项目概述 后端&#xff1a;Springboot、mybatis-plus、java 前端&#xff1a;nodejs、vue脚手架、element-ui 数据…

研发工程师玩转Kubernetes——PVC使用Label和storage选择PV

在《研发工程师玩转Kubernetes——local型PV和PVC绑定过程中的状态变化》和《研发工程师玩转Kubernetes——使用local型PV在不同Pod上共享数据》中&#xff0c;我们介绍了指定VPC的spec.volumeName为PV名称来绑定它们的方法。本文将介绍PVC在创建时&#xff0c;系统自动选择绑定…

GEE学习04-

0 回顾 之前学习的内容可以概括为&#xff1a; conda activate gee cd /d e:/geelearn jupyter lab可以在prompt中chrlc停止当前打开的jupyter lab. import ee #ee.Authenticate() import geemap geemap.set_proxy(port 1080) map geemap.Map() map1、视频课学习 之后跟着…

SonarQube安装与Java、PHP代码质量分析扫描

文章目录 1、下载安装1.1、SonarQube下载1.2、SonarQube安装1.3、SonarQube中文汉化1.4、SonarScanner扫描器 2、扫描项目2.1、java代码扫描2.2、php代码扫描 1、下载安装 SonarQube负责存储代码数据、收集数据、分析代码和生成报告等。 1.1、SonarQube下载 下载地址&#x…

【TypeScript】类型断言-类型的声明和转换(五)

【TypeScript】类型断言-类型的声明和转换&#xff08;五&#xff09; 【TypeScript】类型断言-类型的声明和转换&#xff08;五&#xff09;一、简介二、断言形式2.1 尖括号语法2.2 as形式 三、断言类型3.1 非空断言3.2 肯定断言-肯定化保证赋值3.3 将任何类型断言为any3.4 调…

ngrok内网穿透可以实现资源共享吗?快解析更加简洁

随着互联网的高速发展&#xff0c;越来越多的人开始意识到内网穿透技术的重要性。在这一技术中&#xff0c;ngrok已经成为了一个备受关注的工具。然而&#xff0c;很多人对于ngrok是否可以进行资源共享存在疑问。本文将从新的角度出发&#xff0c;深入探讨这个问题。 了解什么…

要实现智能制造到底有多难?先看看这一步...

是新朋友吗&#xff1f;记得先点上方蓝字关注Ruff 智能制造、数字化转型&#xff0c;已成为当下制造业最炙手可热的话题&#xff0c;政府工作报告中已多次提到&#xff0c;为了促进数字经济发展&#xff0c;加强数字中国建设整体布局&#xff0c;打造智能工厂、智慧工厂。愿景是…

【Linux】-- 进程间通信

目录 一、进程间通信介绍 二、管道 1.什么是管道&#xff08;pipe&#xff09; 2.重定向和管道 &#xff08;1&#xff09;为什么要有管道的存在 &#xff08;2&#xff09;重定向和管道的区别 3.匿名管道 &#xff08;1&#xff09;匿名管道原理 &#xff08;2&…

mysql索引的数据结构(Innodb)

首选要注意,这里的数据结构是存储在硬盘上的数据结构,不是内存中的数据结构,要重点考虑io次数. 一.不适合的数据结构: 1.Hash:不适合进行范围查询和模糊匹配查询.(有些数据库索引会使用Hash,但是只能精准匹配) 2.红黑树:可以范围查询和模糊匹配,但是和硬盘io次数比较多. 二…

机器学习笔记 - 关于GPT-4的一些问题清单

一、简述 据报道,GPT-4 的系统由八个模型组成,每个模型都有 2200 亿个参数。GPT-4 的参数总数估计约为 1.76 万亿个。 近年来,得益于 GPT-4 等高级语言模型的发展,自然语言处理(NLP) 取得了长足的进步。凭借其前所未有的规模和能力,GPT-4为语言 AI​​设立了新标准,并为机…

vue-pc端实现按钮防抖处理-自定义指令

前言 我们经常在移动端会处理按钮和输入框的防抖和节流处理&#xff0c;在pc端很少进行这样的操作 但是在pc端也是可以进行按钮的防抖操作&#xff0c;这样也是比较合理&#xff0c;可以不用但不可以不会 我们只要配合vue项目自定义指令加上全局注册&#xff0c;就可以实现按…