求树中两个节点的最低公共祖先
方法一:递归
先处理base case
- root==nullptr ,返回root
- root==p,返回root
- root==q,返回root
这道题就一共有三种特殊情况均直接返回root即可。
根据临界条件,实际上可以发现这道题已经被简化为查找以root为根结点的树上是否有p结点或者q结点,
如果有就返回p结点或q结点,否则返回null。
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root==p||root==q||!root) return root;
//如何看待下面函数:返回的其实是nullptr或者value等于val1或val2的结点
TreeNode* left=lowestCommonAncestor(root->left, p, q);
TreeNode* right=lowestCommonAncestor(root->right, p, q);
//下面的是后序遍历的位置,从下往上,
//左右子树都没有p结点或者q结点
if(!left&&!right)return NULL;
//左子树有p结点或者q结点,右子树为nullptr
else if(left&&!right)return left;
//右子树有p结点或者q结点,左子树为nullptr
else if(right&&!left)return right;
//左右子树都有p结点或者q结点
//表明val1,val2分别位于root的左右,此时root就是他们的最近公共祖先
return root;
}
方法二:记录路径
先求出root到a的路径,保存下来,在求出root到b的路径,保存下来。
于是问题变成了两个单链表相交,求交点的问题了。
先想一想怎么记录root到p的路径,类比回溯法
#include<list>
using namespace std;//vector和list在命名空间std里,还需要添加声明 using namespace std;
list<TreeNode*> path;
bool getNodePath(TreeNode* root,TreeNode* p,list<TreeNode*>& path){
//base case:特殊情况
if(root==nullptr||p==nullptr) return false;
if(root==p)
{
//记录路径
path.push_back(root);
return true;
}
//记录路径
path.push_back(root);
bool found=false;
//左子树中找
found=getNodePath(root->left,p,path);
//左子树没有,则去右子树中找
if(!found)
found=getNodePath(root->right,p,path);
//深刻理解了后序遍历,才能理解在这里撤销的目的
//首先,递归框架会遍历树中所有结点,
//其次,每个子树都是先左,再右,最后根
//撤销
//左右子树都没有,则撤销路径
if(!found)
path.pop_back();
return found;
}
在想想两个单链表相交,求交点的问题
方法很多,可以看看判断两个单链表是否相交及找到第一个交点
这里可以直接用求链表长度的方法求出两个链表的长度:len_a,len_b,求出差值len(len为较大的减去较小的值)。让长的那个先走len步,之后两个链表一起走,直至走到相同的节点。