Leetcode 236. 二叉树的最近公共祖先

Leetcode 236. 二叉树的最近公共祖先

1、问题分析

题目链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/
  本质上就是一个二叉树的遍历问题。代码我已经进行了详细的注释,理解应该没有问题,读者可以作为参考,如果看不懂(可以多看几遍),欢迎留言哦!我看到会解答一下。

2、问题解决

  笔者以C++方式解决。

#include "iostream"

using namespace std;

#include "algorithm"
#include "vector"
#include "queue"
#include "set"
#include "map"
#include "string"
#include "stack"

/**
* Definition for a binary tree node.
* struct TreeNode {
*     int val;
*     TreeNode *left;
*     TreeNode *right;
*     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;

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

class Solution {
    // 存储 p 节点的所有父节点 (包括节点本身)
    vector<TreeNode *> parentA;
    // 存储 q 节点的所有父节点 (包括节点本身)
    vector<TreeNode *> parentB;
public:
    TreeNode *lowestCommonAncestor(TreeNode *root, TreeNode *p, TreeNode *q) {
        // 如果树为空,直接返回空
        if (root == NULL) {
            return root;
        }
        // 返回二叉树的最近公共祖先
        return dealChen(root, p, q);
    }

    /**
     * 搜寻二叉树的最近公共祖先
     * @param root
     * @param p
     * @param q
     * @return
     */
    TreeNode *dealChen(TreeNode *root, TreeNode *p, TreeNode *q) {
        // 初始化 flag 默认为 0,表示满意找到节点; 1 代表找到节点
        int flag = 0;
        // 计算 p 节点的所有父节点 (包括节点本身)
        inorder(root, flag, p, parentA);
        flag = 0;
        // 计算 q 节点的所有父节点 (包括节点本身)
        inorder(root, flag, q, parentB);

        // 由于保存的节点,都是从目标节点到根节点的顺序
        // 所以直接从目标节点本身开始比较,相等的就是最近的公共祖先
        for (int i = 0; i < parentA.size(); ++i) {
            for (int j = 0; j < parentB.size(); ++j) {
                if (parentA[i] == parentB[j]) {
                    return parentA[i];
                }
            }
        }

        // 没有公共祖先
        return NULL;
    }

    /**
     * 中序遍历寻找 target 节点的所有父节点
     * @param root 当前正在处理的节点
     * @param flag 是否找到  target 节点 的标志位
     * @param target 目标节点
     * @param parent 父节点的保存地址
     */
    void inorder(TreeNode *root, int &flag, TreeNode *target, vector<TreeNode *> &parent) {
        // 当前正在处理的节点不为空
        if (root != NULL) {
            // 中序遍历
            inorder(root->left, flag, target, parent);
            // 如果左子树遍历之后,目标节点节点被找到了,说明肯定是从当前节点出去找的
            // 也就是当前节点是 目标节点 的父节点
            if (flag == 1) {
                // 保存父节点
                parent.push_back(root);
                return;
            }
            // 找到目标节点
            if (root->val == target->val) {
                // 设置是否找到  target 节点 的标志位为 已找到
                flag = 1;
                // 保存目标节点
                parent.push_back(root);
                return;
            }
            inorder(root->right, flag, target, parent);
            // 如果右子树遍历之后,目标节点节点被找到了,说明肯定是从当前节点出去找的
            // 也就是当前节点是 目标节点 的父节点
            if (flag == 1) {
                // 保存父节点
                parent.push_back(root);
                return;
            }
        }


    }

};


int main() {

    TreeNode *pNode0 = new TreeNode(0);
    TreeNode *pNode1 = new TreeNode(1);
    TreeNode *pNode2 = new TreeNode(2);
    TreeNode *pNode3 = new TreeNode(3);
    TreeNode *pNode4 = new TreeNode(4);
    TreeNode *pNode5 = new TreeNode(5);
    TreeNode *pNode6 = new TreeNode(6);
    TreeNode *pNode7 = new TreeNode(7);
    TreeNode *pNode8 = new TreeNode(8);

    pNode3->left = pNode5;
    pNode3->right = pNode1;
    pNode5->left = pNode6;
    pNode5->right = pNode2;
    pNode1->left = pNode0;
    pNode1->right = pNode8;
    pNode2->left = pNode7;
    pNode2->right = pNode4;


    Solution *pSolution = new Solution;
    TreeNode *pNode = pSolution->lowestCommonAncestor(pNode3, pNode8, pNode5);
    if (pNode != NULL) {
        cout << pNode->val << endl;
    }

    system("pause");
    return 0;
}

运行结果

在这里插入图片描述

有点菜,有时间再优化一下。

3、总结

  难得有时间刷一波LeetCode, 这次做一个系统的记录,等以后复习的时候可以有章可循,同时也期待各位读者给出的建议。算法真的是一个照妖镜,原来感觉自己也还行吧,但是算法分分钟教你做人。前人栽树,后人乘凉。在学习算法的过程中,看了前辈的成果,受益匪浅。
感谢各位前辈的辛勤付出,让我们少走了很多的弯路!
哪怕只有一个人从我的博客受益,我也知足了。
点个赞再走呗!欢迎留言哦!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值