leetcode 236 二叉树的公共祖先

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]

在这里插入图片描述
示例 1:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3。
示例 2:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出: 5
解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。
说明:
所有节点的值都是唯一的。
p、q 为不同节点且均存在于给定的二叉树中。
问题思考:
1、两个节点的公共祖先一定在从根节点,至这两个节点的路径上。
2、由于求公共祖先中的最近公共祖先,那么即同时出现在这两条路径上的离根节点最远的节点
3、最终算法即为:求p节点路径,q节点路径,两路径上最后一个相同的节点
思路:
1、从根节点遍历至该节点,找到该节点后就结束搜索。
2、将遍历过程中遇到的节点按照顺序存储起来,这些节点即路径节点
在深度优先搜索的条件下,前序指在未访问该节点左右子树时,对这个节点所做的一些操作,中序是代表在访问完左子树之后所做的一些操作,后序指左右子树遍历完成,再回退到上一个节点的时候所做的一些操作,三种遍历方式的区别是在深度搜索的不同位置进行的一些操作。

 void preorder(TreeNode *node,  //正在遍历的节点
                  TreeNode *search,  //待搜索节点
                  std::vector<TreeNode*> &path, //遍历时的节点路径栈
                  std::vector<TreeNode*> &result,  //最终搜索到节点search的路径结果
                  int &finish){  //记录是否找到节点search的变量,未找到时是0,找到为1
        if (!node || finish){
            return;
        }
        path.push_back(node);  //先序遍历时,将节点压入path栈
        if (node == search){
            finish = 1;    //当找到search节点后,标记finish变量
            result = path;  //将当前的path存储到result中
        }
        preorder(node->left, search, path, result, finish);   //深度遍历node的左孩子
        preorder(node->right, search, path, result, finish);    //深度遍历node的右孩子
        path.pop_back(); //结束遍历node时,将node节点弹栈
    }

3、求出较短路径的长度n
4、同时遍历p节点的路径与q节点的路径,遍历n个节点,最后一个发现的相同节点,即最近公共祖先。
完整代码如下:

/**
 * 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) {
        std::vector<TreeNode*> path;   //声明遍历用的临时栈
        std::vector<TreeNode*> node_p_path;  //存储p节点路径
        std::vector<TreeNode*> node_q_path;  //存储q节点路径
        int finish = 0;  //记录是否完成搜索的变量finish
        preorder(root, p, path, node_p_path, finish);
        path.clear(); 
        finish = 0;    //清空path、finish、计算q节点路径
        preorder(root, q, path, node_q_path, finish);
        int path_len = 0;  //较短路径的长度
        if(node_p_path.size() < node_q_path.size()) {
            path_len = node_p_path.size();
        }
        else{
            path_len = node_q_path.size();
        }
        TreeNode *result = 0;   //同时遍历到p、q两个节点的路径上的节点
        for (int i = 0; i < path_len; i++){
            if (node_p_path[i] == node_q_path[i]) {
                result = node_p_path[i];
            }
        }
        return result;
    }
private:
    void preorder(TreeNode *node,  //正在遍历的节点
                  TreeNode *search,  //待搜索节点
                  std::vector<TreeNode*> &path, //遍历时的节点路径栈
                  std::vector<TreeNode*> &result,  //最终搜索到节点search的路径结果
                  int &finish){  //记录是否找到节点search的变量,未找到时是0,找到为1
        if (!node || finish){
            return;
        }
        path.push_back(node);  //先序遍历时,将节点压入path栈
        if (node == search){
            finish = 1;    //当找到search节点后,标记finish变量
            result = path;  //将当前的path存储到result中
        }
        preorder(node->left, search, path, result, finish);   //深度遍历node的左孩子
        preorder(node->right, search, path, result, finish);    //深度遍历node的右孩子
        path.pop_back(); //结束遍历node时,将node节点弹栈
    }
};
发布了65 篇原创文章 · 获赞 4 · 访问量 998

猜你喜欢

转载自blog.csdn.net/CLZHIT/article/details/103939247
今日推荐