每日一算法题-最近共同祖先

132 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第12天,点击查看活动详情

一、题目

给定一颗二叉树,保证每个节点的值不相同,请通过同时给出的两个节点所对应的值v1和v2去查找这两个节点的最近共同祖先节点。

image.png

#include<iostream>
using namespace std;

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

int closestAncestor(TreeNode* root, int o1, int o2) {
}

int main(int, char*[])
{
    TreeNode root(3);
    TreeNode node1(5);
    TreeNode node2(1);
    TreeNode node3(6);
    TreeNode node4(2);
    TreeNode node5(7);
    TreeNode node6(4);
    TreeNode node7(0);
    TreeNode node8(8);
    root.left = &node1;
    root.right = &node2;
    node1.left = &node3;
    node1.right = &node4;
    node4.left = &node5;
    node4.right = &node6;
    node2.left = &node7;
    node2.right = &node8;

    cout << "最近的共同祖先是:" << closestAncestor(&root, 2, 7) << endl;
}

二、分析

由题意可知:
每个节点值都不同,可得出每个节点只会跟v1或者v2其中一个相等。
由此特性,我们在遍历的时候可以保证只要找到一个节点后是不会再重复的,所以再回溯的时候就不需要记录找到的这个节点是v1还是v2。

与二叉搜索树一样,也是需要通过比较得出结论,不同的是,这次需要同时比较两个节点。
但是没有比较顺序,所以是用先序、中序、后序其实都是可行的,但是从比较的效率来看,左右的比较需要遍历很多次,而根的比较只有一次,所以同等概率下先序和中序的效率是要高一些的。

三、模拟

  1. -> 3 没找到
  2. 3 -> 5 没找到
  3. 5 -> 6 没找到
  4. 6 -> 5
  5. 5 -> 2 找到2,未全部找到,继续
  6. 2 -> 7 找到7,未全部找到,继续
  7. 7 -> 2 带着找到一个的结果,与2一起,便找到两个

四、实现

bool dfs(TreeNode* root, int o1, int o2, int* &result){
    if(!root || result) return false;
    bool s = (root->val == o1 ||root->val == o2);
    bool l = dfs(root->left, o1, o2, result);
    if(result) return false;
    if(s && l){
        result = &root->val;
        return false;
    }else if(s || l){
        bool r = dfs(root->right, o1, o2, result);
        if(r){
            result = &root->val;
        }
        return true;
    }else{
        return dfs(root->right, o1, o2, result);
    }
}
int closestAncestor(TreeNode* root, int o1, int o2) {
    int* result = nullptr;
    dfs(root, o1, o2, result);
    return *result;
}

五、结言

这道题也是考验了对二叉树遍历的算法,同时也是一道实用题。

创作不易,留个赞再走吧!如果对文章内容有任何指正,欢迎评论!