当这棵树是一颗普通二叉树时,难度就会增大一些。
还是有两种做法,递归和直接搜索路径
目录
1.递归
如何递归呢,我们知道,在遍历过程中当且仅当当前节点遍历之前如果遍历了两个目标节点,那么第一个这个节点就是要找的最近公共祖先。
我们定义一个函数,这个函数的输入是节点,两个目标值
函数的含义如下:
若返回-1,则说明当前节点不是最近公共祖先。
若传给其左子树的根,返回值为-1,说明左子树也不是最近公共祖先。
对于右子树则和左子树的情况一样。
另外一种情况是如果返回的不是-1,比如说左子树返回不是-1,则说明左子树是一个目标值的祖先,那么我们的任务就是找到第一个左右子树返回都不是-1的节点。
那什么时候我们的函数不返回-1呢?当然是遇到目标值的时候。
代码如下所示:
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
class Solution {
public:
/**
*
* @param root TreeNode类
* @param o1 int整型
* @param o2 int整型
* @return int整型
*/
int lowestCommonAncestor(TreeNode* root, int o1, int o2) {
// write code here
if(root==NULL){
return -1;
}
if(root->val==o1 || root->val==o2){
return root->val;
}
int left=lowestCommonAncestor(root->left, o1, o2);
int right=lowestCommonAncestor(root->right, o1, o2);
if(left==-1){
return right;
}
if(right==-1){
return left;
}
return root->val;
}
};
2.搜索路径
这里的思路就是一遍dfs啦:
有几个要注意的细节:
1.设置一个flag,想一下我们如果找到了目标值的路径是不是得结束我们的寻找,没错,就是类似于剪枝。关于这个flag的位置要放在两个地方,一是开头,二是回溯之前,递归之后,细节大家应该明白。
2.回溯:很重要的一点啦,我们递归完当前节点,由于我们原来把他放到了vector中,我们在退回的时候当然得回溯啦。
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
class Solution {
public:
/**
*
* @param root TreeNode类
* @param o1 int整型
* @param o2 int整型
* @return int整型
*/
bool flag=false;
void dfs(TreeNode *root, vector<int> &path, int o){
if(root==NULL || flag){
return;
}
path.push_back(root->val);
if(root->val==o){
flag=true;
return;
}
dfs(root->left, path, o);
dfs(root->right, path, o);
if(flag) return;
path.pop_back();
}
int lowestCommonAncestor(TreeNode* root, int o1, int o2) {
// write code here
vector<int> path1, path2;
dfs(root, path1, o1);
flag=false;
dfs(root, path2, o2);
int res=-1;
for(int i=0;i<path1.size()&&i<path2.size();++i){
if(path1[i]==path2[i]){
res=path1[i];
}else{
break;
}
}
return res;
}
};