维基百科:
根据维基百科中对最近公共祖先节点的定义:“两个节点 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;
}
};