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

news2025/3/12 1:20:04

文章目录

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

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

一、题目

在这里插入图片描述
在这里插入图片描述

二、解法

  思路分析: 根据定义,最近祖先节点需要遍历节点的左右子树,然后才能知道是否为最近祖先节点。那么这种需求是先遍历左右节点,然后遍历中间节点,属于左右中的后序遍历模式。因此在程序当中,我们选择递归中序遍历。输入参数为根节点p q节点。终止条件是当前节点和p q当中任意一个节点相等时就返回,遍历到空节点也返回。因为是后序遍历,根据遍历完左右子树后的返回值确定返回参数,如果返回值都不为空,则当前节点就是最近祖先节点。如果left为空,right不为空,则最近祖先节点在右子树,反之亦然。均为空则返回NULL
  程序如下

class Solution2 {
public:
    // 后序遍历: 左右中
    // 1、输入参数
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        // 2、终止条件
        if (root == q || root == p || root == NULL) return root;    // 如果节点相等或者是空节点返回

        // 3、单层递归逻辑
        TreeNode* left = lowestCommonAncestor(root->left, p, q);        // 左
        TreeNode* right = lowestCommonAncestor(root->right, p, q);      // 右

        // 1、返回值
        if (left != NULL && right != NULL) return root;
        if (left == NULL && right != NULL) return right;
        else if (left != NULL && right == NULL) return left;
        else { //  (left == NULL && right == NULL)
            return NULL;
        }
    }
};

  代码优化

class Solution {
public:
    // 后序遍历: 左右中
    // 1、输入参数
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        // 2、终止条件
        if (root == p || root == q || root == NULL) return root;    // 如果节点相等或者是空节点返回

        // 3、单层递归逻辑
        TreeNode* left = lowestCommonAncestor(root->left, p, q);        // 左
        TreeNode* right = lowestCommonAncestor(root->right, p, q);      // 右
        if (left != NULL && right != NULL) return root;
        if (left == NULL) return right;

        // 1、返回值
        return left;
    }
};

三、完整代码

# 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 == p || root == q || root == NULL) return root;    // 如果节点相等或者是空节点返回

        // 3、单层递归逻辑
        TreeNode* left = lowestCommonAncestor(root->left, p, q);        // 左
        TreeNode* right = lowestCommonAncestor(root->right, p, q);      // 右
        if (left != NULL && right != NULL) return root;
        if (left == NULL) return right;

        // 1、返回值
        return left;
    }
};

class Solution2 {
public:
    // 后序遍历: 左右中
    // 1、输入参数
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        // 2、终止条件
        if (root == q || root == p || root == NULL) return root;    // 如果节点相等或者是空节点返回

        // 3、单层递归逻辑
        TreeNode* left = lowestCommonAncestor(root->left, p, q);        // 左
        TreeNode* right = lowestCommonAncestor(root->right, p, q);      // 右

        // 1、返回值
        if (left != NULL && right != NULL) return root;
        if (left == NULL && right != NULL) return right;
        else if (left != NULL && right == NULL) return left;
        else { //  (left == NULL && right == NULL)
            return NULL;
        }
    }
};

// 前序遍历迭代法创建二叉树,每次迭代将容器首元素弹出(弹出代码还可以再优化)
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 = { "3", "5", "6", "NULL", "NULL", "2", "7", "NULL", "NULL", "4", "NULL", "NULL", "1", "0", "NULL", "NULL", "8", "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 = 5, q = 1;
    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

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

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

相关文章

【ccf-csp题解】第0次csp认证-第四题-有趣的数-组合数学

题目描述 思路说明 本题涉及组合数学的知识 目的是在n个空位上放置0、1、2、3&#xff0c;问符合题意的放法有多少种 首先注意到一个重要的事实&#xff1a; 只要0和1的位置已经确定&#xff0c;那么2和3的摆放就十分容易了 那么把所有情况分为n-2种&#xff1a; 第一种…

IntelliJ IDEA 配合 Maven 的一些技巧(prifiles)

环境 IntelliJ IDEA 2017.1 Maven 3.3.9 Nexus 3.2.1 学习前提 了解 Maven 配置的基本用法 了解私有仓库&#xff0c;比如 nexus 的一些概念 强烈建议把 Maven 的 settings.xml 文件同时放在&#xff1a;%USER_HOME%/.m2/settings.xml 和 ${maven.home}/conf/settings.xm…

给 Ubuntu 操作系统配置静态 IP

针对 Ubuntu 22.04.3 操作系统的静态 IP 配置 一、查看初始的网络信息 查看网卡名称 ifconfig查看网关信息 route -n二、编辑网络配置文件 编辑文件&#xff0c;配置文件的名称可能不一样&#xff0c;自己去 /etc/netplan/ 目录查看 sudo vim /etc/netplan/01-network-manager-…

51单片机的智能台灯控制系统仿真( proteus仿真+程序+原理图+报告+讲解视频)

51单片机的红外光敏检测智能台灯控制系统仿真 1.主要功能&#xff1a;2.仿真3. 程序代码4. 原理图5. 设计报告6. 设计资料内容清单&&下载链接 51单片机的红外光敏检测智能台灯控制系统仿真( proteus仿真程序原理图报告讲解视频&#xff09; 仿真图proteus7.8及以上 程…

服务器时间正确,Java程序时区不对问题解决

服务器执行date命令显示时间正确 执行timedatectl status命令结果如下&#xff1a; 看起来是Time zone没有设置好&#xff0c;但是登录另外一台正常的服务器&#xff0c;执行timedatectl status也是一样的 直接写一个简单的Java程序TestTimeZone.java&#xff1a; import ja…

consul 键值对操作命令

1. 创建或更新—>put [rootlocalhost ~]# consul kv put redis/config/connection 5 Success! Data written to: redis/config/connection[rootlocalhost ~]# consul kv put aaaaaaaaaaaa 5 Success! Data written to: aaaaaaaaaaaa /redis/config会生成两个目录&#xff…

【小吉送书—第二期】阿里后端开发:抽象建模经典案例

文章目录 0.引言1.抽象思维2.软件世界中的抽象2.1 命名抽象2.2 分层抽象2.3 原则抽象 3. 经典抽象案例3.1 方案一&#xff1a;战术抽象&#xff0c;多快好省&#xff0c;跑步前进3.2 方案二&#xff1a;深入分析&#xff0c;透过表象&#xff0c;探寻本质 5. 推荐一本书&#x…

基于奇偶模的跨线桥(crossover)分析

文章目录 1、ADS建模2、奇偶模分析2.1 Port1→Port2传输特性2.1.1奇模分析2.1.2偶模分析 2.2 Port1→Port4传输特性 附&#xff1a;正交混合网络的奇偶模分析1、 Port1→Port21.1奇模分析1.2Port1→Port2偶模分析1.3 奇模传输与偶模传输相位关系![在这里插入图片描述](https://…

鸿蒙开发实例 |搭建环境

2019年8月9日&#xff0c;华为在东莞举行华为开发者大会&#xff0c;正式发布鸿蒙操作系统&#xff1b;2020年9月推出了鸿蒙2.0&#xff0c;全面使能全场景生态&#xff0c;具备跨设备、服务流转、极速直达、可视可说、隐私安全五大能力。在2021年6月2日的华为新品发布会中&…

ChatGPT很好,但别想着用来写留学申请文书!

大家必须承认一件事&#xff0c;大多数申请者和 ChatGPT 相比&#xff0c;ChatGPT 产出的文章质量更高—— ChatGPT语言更精准 ChatGPT文章结构更严谨 ChatGPT行文更流畅 …… 但是为什么仍然不建议大家利用人工智能来撰写申请文书呢&#xff1f; 文书至关重要——比大…

IntelliJ IDEA 配合 Maven 的一些技巧(profiles)

IntelliJ IDEA 配合 Maven 的一些技巧 环境 IntelliJ IDEA 2017.1 Maven 3.3.9 Nexus 3.2.1 ## 学习前提 了解 Maven 配置的基本用法 了解私有仓库&#xff0c;比如 nexus 的一些概念 强烈建议把 Maven 的 settings.xml 文件同时放在&#xff1a;%USER_HOME%/.m2/settin…

IDEA中DEBUG技巧

Debug 介绍 Debug 设置 如上图标注 1 所示&#xff0c;表示设置 Debug 连接方式&#xff0c;默认是 Socket。Shared memory 是 Windows 特有的一个属性&#xff0c;一般在 Windows 系统下建议使用此设置&#xff0c;相对于 Socket 会快点。 ## Debug 常用快捷键 Win 快捷键M…

初高(重要的是高中)中数学知识点综合(持续更新)

1. 集合 1.1 集合的由来和确定性 确定对象构成的整体称为集合&#xff08;组成集合的元素必须是确定的 &#xff09;&#xff0c;每个集合内的对象个体成为元素(Element)。确定性&#xff1a; 给定一个集合&#xff0c;任何一个对象是不是这个集合内的元素&#xff0c;就已经确…

港联证券股票分析:经济拐点显现 积极提升仓位

港联证券指出&#xff0c;商场底部上升的方向不变&#xff0c;当时稳增加和活跃资本商场的活跃方针仍在持续落地&#xff0c;一起也看到了一些经济数据边沿企稳的迹象&#xff0c;跟着方针作用的进一步闪现&#xff0c;商场情绪有望持续好转&#xff0c;上市公司基本面也有望得…

vue+element使用阿里的图标库保存图标

阿里图标网站iconfont-阿里巴巴矢量图标库 我想使用保存图标&#xff0c;但是element的图标库没有找到可用的&#xff0c;首先在阿里的图标网站搜索保存 发现这个还不错 点击添加入库 点击购物车 点击添加至项目 点击下载到本地 把下载的压缩包里面的文件拖到自己项目里面 在m…

ICCV 2023 | SuS-X:仅靠类别名称微调CLIP模型,剑桥大学联合DeepMind出品

论文链接&#xff1a; https://arxiv.org/abs/2211.16198 代码仓库&#xff1a; https://github.com/vishaal27/SuS-X 对比语言图像预训练&#xff08;Contrastive Language-Image Pre-training&#xff0c;CLIP&#xff09; 已成为计算机视觉社区通向自然语言领域的一种常用的…

mp4视频太大怎么发送?这样压缩视频就对了

随着科技的发展&#xff0c;视频格式多种多样&#xff0c;其中mp4格式因为其通用性而广受欢迎。然而&#xff0c;有时候我们会遇到一个问题&#xff1a;mp4视频文件太大&#xff0c;导致发送变得困难。那么&#xff0c;如何解决这个问题呢&#xff1f;下面就给大家分享几个实用…

【易盾点选】

拿官网的点选做个例子吧&#xff0c;比较省事&#xff0c;水一篇~ ​ 官网的接口目前都改成V3了&#xff0c;多了个dt参数&#xff0c;以及加密的一个函数也变动了下 点选坐标在这&#xff0c;加密函数未变&#xff0c;用逗号拼接 整个加密里的函数变了&#xff0c;直接重新…

live555-lastest 编译

1. live555-latest 源码下载&#xff1a;http://www.live555.com/ 2. 将下载的live-latest.tar.gz放到指定目录下解压&#xff1a;tar -xvf live-latest.tar.gz&#xff0c;cd 进入live目录&#xff0c;在live目录下有很多config.xxxx的相关配置文件&#xff0c;config.linux默…

什么是Vercel?

Vercel 是一个云平台&#xff0c;用于构建、部署和扩展无服务器应用程序和静态网站。由于其易用性、速度和处理大量流量的能力&#xff0c;它在开发人员中越来越受欢迎。 使用 Vercel&#xff0c;您可以使用各种编程语言和框架构建和部署应用程序&#xff0c;并利用自动 SSL、…