程序员面试金典 4.8

First Common Ancestor:设计一个算法,查找树中两个节点的最近公共祖先节点。

如果是二叉搜索树,可以修改查找操作,看看两个节点在哪个节点进行分支,该节点就是最近公共祖先。

1种方法要使用父指针。如果每个节点有链接到父节点的指针,则可以通过父指针一直向上回溯,直到遇到相交节点,类似于找两个链表的交点,算法复杂度和更深的节点相关,但是力扣上没有父指针。

2种方法也需要父指针。在回溯到p的父节点时,为了确定该节点是否是最近公共祖先,需要在p的兄弟节点中查找q,算法复杂度和最近公共祖先的子树大小相关。

3种不需要父指针。通过从根节点开始搜索pq的所处的子树:

  • 如果根节点就是p或者q,则根节点就是最近公共祖先
  • 如果都在左子树,则就在左子树中查找最近公共祖先
  • 如果都在右子树,则就在右子树中查找最近公共祖先
  • 否则根节点就是最近公共祖先
/**
 * 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(!exist(root, p) || !exist(root, q)) return nullptr;
        return CommonAncestor(root, p, q);
    }
private:
    bool exist(TreeNode *root, TreeNode *n)
    {
        if(root == nullptr) return false;
        else if(root == n) return true;
        else return exist(root->left, n) || exist(root->right, n);
    }
    TreeNode* CommonAncestor(TreeNode *root, TreeNode *p, TreeNode *q)
    {
        if(root == p || root == q) return root;
        bool bPLeft = exist(root->left, p);
        bool bQLeft = exist(root->left, q);
        if(bPLeft && bQLeft){
            return CommonAncestor(root->left, p, q);
        }
        else if(!bPLeft && !bQLeft){
            return CommonAncestor(root->right, p, q);
        }
        else return root;
    }
};

虽然会进行折半查找,但是再确定进入哪一半时另一半也需要遍历,所以算法复杂度为O(n)。尽管时间复杂度已经很好了,但是exist()会进行多次重复的遍历,如果每个节点只被访问一次就好了。对于一棵树,最近公共祖先可能是根节点,可能在左子树,也可能在右子树:

  • 如果根节点就是p或者q,则根节点就是最近公共祖先
  • 否则在左子树中查找,可能找到最近公共祖先,也可能找到p或者q,需要根据对右子树进行类似查找的情况区分这两种情况
/**
 * 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 == nullptr || root == p || root == q) return root;
        TreeNode* left = lowestCommonAncestor(root->left, p, q);
        TreeNode* right = lowestCommonAncestor(root->right, p, q);
        if(left != nullptr && right != nullptr) return root;
        else if(left != nullptr) return left;
        else return right; 
    }
};
发布了194 篇原创文章 · 获赞 2 · 访问量 7732

猜你喜欢

转载自blog.csdn.net/RayoNicks/article/details/105324739
4.8
今日推荐