题目

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 pq,最近公共祖先表示为一个节点 x,满足 xpq 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

示例 1:
image.png

  1. 输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
  2. 输出:3
  3. 解释:节点 5 和节点 1 的最近公共祖先是节点 3

示例 2:
image.png

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出:5
解释:节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。

示例 3:

输入:root = [1,2], p = 1, q = 2
输出:1

提示:

  • 树中节点数目在范围 [2, 10^5] 内。
  • -10^9 <= Node.val <= 10^9
  • 所有 Node.val 互不相同 。
  • p != q
  • pq 均存在于给定的二叉树中。

    解题方法

    递归

    递归判断当前节点是否最近公共祖先,最近公共祖先的成立条件如下:
    (left&&right) || ( (cur->val==p->val)||(cur->val==q->val) && (left||right) )
    其中:left代表当前节点的左子树中存在任意目标元素,right代表当前节点的右子树中存在任意目标元素。
    递归终止条件为:
    cur==NULL时返回f否则返回false
    否则递归判断左右子树及当前节点后,返回left || right || cur->val==p->val ||cur->val==q->val
    时间复杂度O(n),空间复杂度O(n)
    c++代码:

    /**
    * Definition for a binary tree node.
    * struct TreeNode {
    *     int val;
    *     TreeNode *left;
    *     TreeNode *right;
    *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
    * };
    */
    class Solution {
    private:
      TreeNode* result;
    public:
      bool dfs(TreeNode* root, TreeNode* p, TreeNode* q) {
          if(!root)   return false;
          bool left = dfs(root->left, p, q);
          bool right = dfs(root->right, p, q);
          if((left&&right) || ((root->val==p->val || root->val==q->val) && (left||right)))    result = root;
    
          return left || right || root->val==p->val || root->val==q->val;
      }
    
      TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
          dfs(root, p, q);
          return result;
      }
    };
    

    递归2

    直接递归返回左右子树中包含包含pq的节点(包括只包含pq和两者都包含),再判断当前节点是否为最近公共祖先。
    时间复杂度O(n),空间复杂度O(n)
    C++代码:

    /**
    * Definition for a binary tree node.
    * struct TreeNode {
    *     int val;
    *     TreeNode *left;
    *     TreeNode *right;
    *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
    * };
    */
    class Solution {
    public:
      TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
          if(root==p || root==q || !root) return root;
          TreeNode* left = lowestCommonAncestor(root->left, p, q);
          TreeNode* right = lowestCommonAncestor(root->right, p, q);
          if(left && right)   return  root;
          else if(left)   return left;
          return right;
      }
    };
    

    哈希表

    通过哈希表重构二叉树,方便查找当前节点的父节点。从pq分别向上遍历,第一个公共父节点即最近公共祖先。
    时间复杂度O(n),空间复杂度O(n)
    C++代码:

    /**
    * Definition for a binary tree node.
    * struct TreeNode {
    *     int val;
    *     TreeNode *left;
    *     TreeNode *right;
    *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
    * };
    */
    class Solution {
    private:
      unordered_map<int, TreeNode*> tree;
      unordered_map<int, bool> vis;
    public:
      void dfs(TreeNode* root) {
          if(!root)   return;
          if(root->left) {
              tree[root->left->val] = root;
              dfs(root->left);
          }
          if(root->right) {
              tree[root->right->val] = root;
              dfs(root->right);
          }
    
      }
    
      TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
          if(!root)   return NULL;
          tree[root->val] = NULL;
          dfs(root);
    
          while(p) {
              vis[p->val] = true;
              p = tree[p->val];
          }
          while(q) {
              if(vis[q->val]) return q;
              q = tree[q->val];
          }
    
          return root;
      }
    };