剑指 Offer 68 - I,II
个人思路
思路
该题要求解最近公共祖先,关键是需要知道给出的两个结点p,q是在左子树还是在右子树,即关键是要知道p,q的准确位置,而不是结点出现的顺序
理一下最初的错误思路,最初是想着如何划分左右子树来找p,q的位置
- 只想到了当一个位于左子树一个位于右子树,则他们的公共祖先是根节点;
- 但两节点存在父子关系,这样的情况还不知道如何处理;
- 还想到了遍历树,因为祖先是存在先后关系的,通过遍历的方法找到最近公共祖先,遍历只能找出祖先出现的顺序,而不能准确得知结点的位置
基础-二叉搜索树
利用二叉搜索树的性质来确定p,q两结点的位置
- 如果当前节点值大于p,q两个节点,说明p,q均在左子树
- 如果当前节点值小于p,q两个节点,说明p,q均在右子树
- 首先找到p,q之间的节点,即为最近公共祖先
一开始看了解析,却还是没有想到如何利用二叉搜索树的性质,还是想采用层序遍历的方法
进阶-普通二叉树
利用递归,搜索左右子树,直到找到p,q来确定两结点的位置
- 递归出口:当前节点为空返回null
- 递归体:递归遍历左子树和右子树,寻找p,q,若当前节点与其中一个相等,说明找到了便返回当前节点;若左子树返回值为null,说明p,q在右子树中,若右子树返回值为null,说明p,q在左子树中,若二者均不为空,说明p,q位于左右两侧,则返回当前节点
个人思路代码
剑指 Offer 68 - I
/**
* 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* ans;
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root == NULL){
return NULL;
}
if(root->val > p->val && root->val > q->val){//当前值大于两个节点的值,说明公共祖先在左子树
return lowestCommonAncestor(root->left, p, q);//返回左子节点
}
else if(root->val < p->val && root->val < q->val){//当前值小于两个节点的值,说明公共祖先在右子树
return lowestCommonAncestor(root->right, p, q);//返回右子节点
}
else{
return root;//返回当前节点
}
return root;
}
};
剑指 Offer 68 - II
/**
* 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 == NULL){
return NULL;
}
if(root == p || root == q){//在左右子树中寻找p,q,找到则说明公共祖先即为root(一个节点也可以是它自己的祖先)
return root;
}
TreeNode* tleft = lowestCommonAncestor(root->left, p, q);//递归遍历左子树,只要在左子树中找到了p或q,则先找到谁就返回谁
TreeNode* tright = lowestCommonAncestor(root->right, p, q);//递归遍历右子树,只要在右子树中找到了p或q,则先找到谁就返回谁
if(tleft == NULL){//在左子树中没有找到p或q,说明pq在右子树中
return tright;
}
else if(tright == NULL){//在右子树中没有找到p或q,说明pq在左子树中
return tleft;
}
else{//到此处,说明左右子树均不为空,应返回根节点
return root;
}
}
};