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

2023-11-07

所有的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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐

  • VTK相机类vtkCamera原理及用法

    vtk是著名的开源三维渲染库 在三维渲染过程中的一个非常重要的内容就是相机即vtkCamera类的设置 在VTK中 相机的实质是一个观测点 VTK的官方Doc对vtkCamera写的十分简略 暗坑很多 在学习和使用vtkCamera的过程中
  • PostgreSQL报pg_dump: no matching tables were found错误

    刚导出表时 发现找不到这个表 但是表是存在的 所以找了一圈 发现是要加 才行 例如 T TABLES
  • python中input()和raw_input()的区别

    两者均是python的内置函数 通过读取控制台的输入与用户实现交互 raw input 将所有输入作为字符串看待 不管用户输入什么类型的都会转变成字符串 raw的含义就是 生的 未加工的 gt gt gt s1 raw input abc
  • Cadence学习篇(1) Cadence原理图工程以及原理图库的创建

    文章目录 前言 一 创建原理图库 1 1新建工程 1 2 设置原理图板框 1 3 设置原理图栅格 二 添加多个原理图 2 1 原理图重命名 2 2 原理图编页码 三 放置元器件 3 1 添加库 3 2 连线 四 保存工程文件 4 1 新建原
  • Larave5.7使用Mailable发送邮件

    现在很多网站都有发送邮件验证身份的功能 所以介绍一下Laravel中邮件发送的方法 Laravel框架中为我们绑定了Mailable服务 我们只需要配置好参数 然后使用该服务即可 配置邮件服务器 我们发送邮件需要有一个stmp服务器 现在有
  • Sublime实现自动排版

    sublime功能很强大 但是使用sublime就可以实现代码自动重新缩进 使代码缩进重排 方法 Ctrl A选中全部内容 然后在菜单中选择Edit gt Line gt Reindent
  • 苹果发布AirTag新固件更新:增加了反跟踪增强功能

    Apple今天发布了专为AirTags设计的1 0 27 固件的新版本 这是对 6 月份提供的更新的修订 新的 AirTags 1 0 276 固件的内部版本号为 1A287b 而旧固件的内部版本号为 1A276d 6 月份发布的 1 0
  • k8s dashboard 报错 Error: 'dial tcp 172.168.56.2:9090: getsockopt: connection refused'

    访问web http 192 168 56 101 8080 ui Error dial tcp 172 17 26 2 9090 getsockopt connection refused 排查方法 1 需要检查apiserver的地址设
  • hive多窗口遇到java.sql.SQLException 异常

    hive多窗口遇到java sql SQLException 异常 多打开一个客户端窗口启动 hive 会产生 java sql SQLException 异常 文章目录 hive多窗口遇到java sql SQLException 异常
  • 【沉浸式腾讯云服务器部署安装docker】

    重置密码 sudo passwd root lighthouse VM 12 2 centos sudo passwd root Changing password for user root New password Retype new
  • asp.net zero 8.2 学习-11-Metronic替换google字体,加速网页加载速度

    asp net zero 8 2使用的前端模板是Metronic6 0以上版本 官网的Metronic下载下来 打开很慢主要是加载googole字体耗费时间 这是我之前写的如何在Metronic中替换google字体 Metronic是一款
  • 使用STM32F4XX自带数学库“arm_math.h“

    使用STM32F4XX自带数学库 arm math h STM32 F4属于Cortex M4F构架 这与M0 M3的最大不同就是具有FPU 浮点运算单元 支持浮点指令集 因此在处理数学运算时能比M0 M3高出数十倍甚至上百倍的性能 但是要
  • 什么是低信噪比图像及处理方法

    信号处理领域的信噪比即SNR Singal to Noise Ration 又称讯噪比 即放大器的输出信号的电压与同时输出的噪声电压的比 常常用分贝数表示 设备的信噪比越高表明它产生的杂音越少 一般来说 信噪比越大 说明混在信号里的噪声越小
  • python (一维、二维)列表的初始化

    一维列表的初始化 初始一个长度为5的列表 方式1 a 0 5 0 0 0 0 0 方式2 a 0 for in range 5 0 0 0 0 0 二维列表的初始化 初始一个2 5的列表 方式1 b 0 5 for in range 2 0
  • Hibernate环境搭建(小实例)

    Hibernate是一个开源的对象关系映射框架 在学习之前 首先让我们先了解一下Hibernate环境是如何搭建的 废话不多说 直接进入正题 建项目 引Jar包 首先 我们需要创建一个Java项目 创建好项目之后 就需要引入与Hiberna
  • unity的HDR效果

    http blog csdn net wolf96 article details 44057915 文章开始先放两组效果 文章结尾再放两组效果 本文测试场景资源来自浅墨大神 shader效果为本文效果 HDR 人们有限的视觉系统 只支持1
  • 【DS】单链表@线性表 —— 增删查改

    目录 0 引 1 链表的概念和结构 2 链表的分类 3 链表的实现 3 1 打印 申请新节点 销毁 3 1 1 打印 3 1 2 申请新节点 3 1 3 销毁 3 2 尾插 尾删 3 2 1 尾插 3 2 2 尾删 3 3 头插 头删 3
  • 物联网场景中,我们如何选择时序数据库 ?

    如今时序数据的应用场景十分广泛 许多类型的数据都是时间序列数据 金融市场交易 传感器测量 水冷 高温 地震 服务器监控 CPU 内存 磁盘 资源消耗 能源 电力 人体健康 心率 血氧浓度 网络访问 通过保留数据固有的时间序列性质 我们可以记
  • mysql:ER_TRUNCATED_WRONG_VALUE_FOR_FIELD: Incorrect string value:

    发现某个组件的表单输入报错 Error ER TRUNCATED WRONG VALUE FOR FIELD Incorrect string value xE6 x88 x91 xE4 xBB xAC for column content
  • 【算法与数据结构】235、LeetCode二叉搜索树的最近公共祖先

    文章目录 一 题目 二 解法 三 完整代码 所有的LeetCode题解索引 可以看这篇文章 算法和数据结构 LeetCode题解 一 题目 二 解法 思路分析 本题和这道题类似 算法与数据结构 236 LeetCode二叉树的最近公共祖先