最近公共祖先结点问题(附力扣题解)

维基百科:

根据维基百科中对最近公共祖先节点的定义:“两个节点 p 和 q 在二叉树 T 中的最近公共祖先节点是后代节点中既包括 p 又包括 q 的最深节点(我们允许一个节点为自身的一个后代节点)”。 一个节点 x 的后代节点是节点 x 到某一叶节点间的路径中的节点 y。

LeetCode(235):

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

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

例如,给定如下二叉搜索树:  root = [6,2,8,0,4,7,9,null,null,3,5]

示例 1:

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

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

说明:

所有节点的值都是唯一的。
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) {
        //寻找公共祖先结点
        TreeNode *node = root;
        while(1) {
            if(node->val > p->val && node->val > q->val) {
                //那么就是说明两个结点都在curnode的左边
                node = node->left;
            }else if(node->val < p->val && node->val < q->val) {
                node = node->right;
            }else {
                break;  //当前就是结点
            }
        }   
        return node;
    }
};

 

LeetCode(236)

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

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

示例 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 。因为根据定义最近公共祖先节点可以为节点本身。
示例 3:

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

提示:

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

具体思路

  • 如果当前的结点为NULL 函数返回NULL
  •  如果 root等于 p 或者 q,那这棵树一定返回 p 或者 q
  • 然后递归左右子树,因为是递归,使用函数后可认为左右子树已经算出结果,用 left 和 right 表示
  • 如果left为空,结果看right ;如果right为空,结果看left
  • 如果left、right都不为空 那么root就是他们的公共祖先结点
/**
 * 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 || root == p || root == q) return root;
        TreeNode* left = lowestCommonAncestor(root->left, p, q);
        TreeNode* right = lowestCommonAncestor(root->right, p, q);
        //分别查找左右子树的最近公共祖先结点是什么
        if(left && right ) {
            //如果都不为空那么就代表root就是
            return root;
        }
        if(left != nullptr) {
            return left;
        }
        if(right != nullptr) {
            return right;
        }
        return nullptr;
    }
};

 

LeetCode(2096):

给你一棵 二叉树 的根节点 root ,这棵二叉树总共有 n 个节点。每个节点的值为 1 到 n 中的一个整数,且互不相同。给你一个整数 startValue ,表示起点节点 s 的值,和另一个不同的整数 destValue ,表示终点节点 t 的值。

请找到从节点 s 到节点 t 的 最短路径 ,并以字符串的形式返回每一步的方向。每一步用 大写 字母 ‘L’ ,’R’ 和 ‘U’ 分别表示一种方向:

‘L’ 表示从一个节点前往它的 左孩子 节点。
‘R’ 表示从一个节点前往它的 右孩子 节点。
‘U’ 表示从一个节点前往它的  节点。
请你返回从 s 到 t 最短路径 每一步的方向。

示例 1:

输入:root = [5,1,2,3,null,6,4], startValue = 3, destValue = 6
输出:”UURL”
解释:最短路径为:3 → 1 → 5 → 2 → 6 。
示例 2:

输入:root = [2,1], startValue = 2, destValue = 1
输出:”L”
解释:最短路径为:2 → 1 。
 

提示:

树中节点数目为 n 。
2 <= n <= 105
1 <= Node.val <= n
树中所有节点的值 互不相同 。
1 <= startValue, destValue <= n
startValue != destValue

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    bool FindPath(TreeNode *root, int target, string& s)
    {
        //寻找第一个的路径
        if(root->val == target) {
            return true;            //如果到达了结点就return掉
        }
        if(root->left) {
            s.push_back('L');
            if(FindPath(root->left, target, s)) return true;   //找到结点就结束了
            s.pop_back();                   //没找到就回溯继续查找
        }
        if(root->right) {
            s.push_back('R');
            if(FindPath(root->right, target, s)) return true;
            s.pop_back();       //回溯删掉路径
        }
        return false;
    }
    string getDirections(TreeNode* root, int startValue, int destValue) {
        //例如 LLRLLR   LLLRLR
        //去掉前缀LL
        //最终结果就是UUUULRLR(因为start是向上找到公共结点 所以方向就完全变身成U)
        //首先找到从根节点到start 与 到dest的路径 去除掉前缀相同的路径就ok
        string str1, str2;
        //找到路径存到str1 str2中
        FindPath(root, startValue, str1);
        FindPath(root, destValue, str2);
        //翻转去掉公共尾巴就相当于去掉公共前缀
        reverse(str1.begin(), str1.end()); reverse(str2.begin(), str2.end());
        while(str1.size() && str2.size() && str1.back() == str2.back()){
            str1.pop_back();
            str2.pop_back();
        }
        //去掉公共前缀后再翻转过来
        reverse(str1.begin(), str1.end()); reverse(str2.begin(), str2.end());
        string ans = string(str1.size(), 'U') + str2;
        return ans;
    }
};

 

Guess you like

Origin blog.csdn.net/qq_52245648/article/details/121876155