Leetcode236、二叉树最近公共祖先

1、问题

已知二叉树,求二叉树中给定的两个节点的最近公共祖先。 最近公共祖先: 两节点v与w的最近公共祖先u,满足在树上最低(离根最 远),且v,w两个节点都是u的子孙。

2、思考与分析

  • 两个节点的公共祖先一定在从根节点,至这两个节点的路径上。

  • 由于求公共祖先中的最近公共祖先,那么即同时出现在这两条路
    径上的离根节点最远的节点(或离两个最近)。

  • 最终算法即:求p节点路径,q节点路径,两路径上最后一个相同的节点。

3、求根节点至某节点路径(栈存储路径)

4、求两路径上最后一个相同的节点

  • 求出较短路径的长度n。
  • 同时遍历p节点的路径与q节点的路径,遍历n个节点,最后一个发现的相 同节点,即最近公共祖先。

5、代码实现

#include 
#include 

using namespace std;

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) {
        // 分两步
        // 1)找到从根结点到节点p的路径p_path;找到从根节点到节点q的路径q_path;
        // 例如:p_path = [3, 5] q_path = [3, 1]
        // 2) 同时遍历p_path和q_path,找到最后一个相等的元素3,即最终结果

        vector< TreeNode* > p_path;
        vector< TreeNode* > q_path;
        vector< TreeNode* > path;  // 临时栈节点
        int finish = 0;  // 标志是否找到待搜索节点
        TreeNode* result = 0;  // 最终返回的最近公共祖先

        // ++++++++++++ 步骤1 +++++++++++++++++
        // 找到节点p的路径
        preorder(root, p, p_path, path, finish);

        // 找到节点q的路径
        path.clear();  // 先清空临时栈路径
        finish = 0;  // 重新置0
        preorder(root, q, q_path, path, finish);

        // ++++++++++++ 步骤2 ++++++++++++++++
        // 同时遍历p_path和q_path
        int min_len;
        if (p_path.size() < q_path.size())
            min_len = p_path.size();
        else
            min_len = q_path.size();

        for (int i = 0; i < min_len; i ++)
        {
            if (p_path[i] == q_path[i])
                result = p_path[i];
        }

        return result;
    }
private:
    // 找到从根结点到某节点的路径
    void preorder(TreeNode* node, TreeNode* search, vector< TreeNode* >& result,
            vector< TreeNode* >& path, int& finish)
    {
        // search是待搜索节点
        // path 是临时存储栈
        // result 是最终找到的结果
        // finish 表示是否已经找到,如果找到置为1,默认为0

        if ( !node || finish == 1)  // 如果node为空(叶节点了)或者finish=1(找到search了)
            return;

        path.push_back(node);  // 当前节点压入到临时栈中

        if ( node == search)
        {
            // 如果找到了
            finish = 1;  // 找到了,即使还没到叶节点,也要返回了
            result = path; // 保存最终结果
        }

        preorder(node->left, search, result,  path, finish);
        preorder(node->right, search, result, path, finish);
        path.pop_back();  // 以当前节点为根的子树搜索完后,弹出该节点,对应的子树也弹出了
    }
};


int main()
{
    TreeNode a(3);
    TreeNode b(5);
    TreeNode c(1);
    TreeNode d(6);
    TreeNode e(2);
    TreeNode f(0);
    TreeNode g(8);
    TreeNode h(7);
    TreeNode i(4);

    a.left = &b;
    a.right = &c;
    b.left = &d;
    b.right = &e;
    c.left = &f;
    c.right=  &g;
    e.left = &h;
    e.right = &i;

    Solution S;
    TreeNode* p = &d;  // 可以改为其他节点
    TreeNode* q = &i;
    TreeNode* res = S.lowestCommonAncestor(&a, p, q);
    cout << res->val << endl;
    return 0;
}

你可能感兴趣的:(Leetcode236、二叉树最近公共祖先)