给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
前面的二叉树思路为:利用回溯从底向上搜索,遇到一个节点的左子树里有p,右子树里有q,那么当前节点就是最近公共祖先。
在有序树里,如果判断一个节点的左子树里有p,右子树里有q呢?
因为是有序树,所有 如果 中间节点是 q 和 p 的公共祖先,那么 中节点的数组 一定是在 [p, q]区间的。即 中节点 > p && 中节点 < q 或者 中节点 > q && 中节点 < p。
那么只要从上到下去遍历,遇到 cur节点是数值在[p, q]区间中则一定可以说明该节点cur就是q 和 p的公共祖先。 那问题来了,一定是最近公共祖先吗?
是的,第一次遇到的cur节点在区间[p, q]之间的,就是最近公共祖先。
1. 确定递归参数及返回值
参数为当前节点,以及两个P, Q;
返回值为最近公共祖先节点。
2. 终止条件
遇到空即可返回
3. 单层递归逻辑
在遍历二叉搜索树的时候就是寻找区间[p->val, q->val](注意这里是左闭又闭)
那么如果 cur->val 大于 p->val,同时 cur->val 大于q->val,那么就应该向左遍历(说明目标区间在左子树上)。
需要注意的是此时不知道p和q谁大,所以两个都要判断
- if (cur->val > p->val && cur->val > q->val) {
- TreeNode* left = traversal(cur->left, p, q);
- if (left != NULL) {
- return left;
- }
- }
整体代码:
- class Solution {
- public:
- TreeNode* traversal(TreeNode* cur, TreeNode* p, TreeNode* q){
- if(cur == NULL) return cur;
-
- if(cur->val > p->val && cur->val > q->val){
- TreeNode* left = traversal(cur->left,p, q);
- if(left != NULL) return left;
- }
- if(cur->val < p->val && cur->val < q->val){
- TreeNode* right = traversal(cur->right,p, q);
- if(right != NULL) return right;
- }
- return cur;
- }
-
- TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
- return traversal(root, p, q);
- }
- };
- class Solution {
- public:
- TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
- while(root){
- if(root->val > p->val && root->val >q->val){
- root = root->left;
- }else if(root->val < p->val && root->val < q->val)
- root = root->right;
- else return root;
- }
- return NULL;
- }
- };