在二叉树中找到两个节点的最近公共祖先:最直观的想法是,数组存储法。首先遍历二叉树,分别找到从根节点到o1与从根节点到o2的路径数组,然后比较两个数组找到最后一个相同的元素即为o1和o2的最近公共祖先。在遍历二叉树的过程中,由于要找的是从根节点到某一节点的路径,故使用前序遍历。其与二叉搜索树的区别是,二叉搜索树的前序遍历的左和右部分都是满足条件再进入循环,而该普通二叉树中没有,故左边返回后可能还会进入右边,这时我们就需要加一个标记是否找到的全局变量flag,在递归终止条件中需要加上当找到即flag为true时则返回,在左右递归遍历结束后还需要判断flag是否为true,如果是则表明找到返回即可,否则表示没找到则要将当前元素弹出数组。
vector<int> path1; vector<int> path2; bool flag=false; // 标记是否找到 // 求解路径数组 void dfs(TreeNode* root,int o,vector<int>& path) { if(flag||!root) return; // 当为空或者已经找到则返回空 path.push_back(root->val); if(root->val==o) { flag=true; // 标记找到 否则后续会继续遍历 return; } dfs(root->left,o,path); dfs(root->right,o,path); // 找到 if(flag) return; // 没找到弹出元素 path.pop_back(); } int lowestCommonAncestor(TreeNode* root, int o1, int o2) { dfs(root,o1,path1); flag=false; // 重置为空 dfs(root,o2,path2); int res; // 记录最后一个相同的 for(int i=0,j=0;i<path1.size()&&j<path2.size();i++,j++) if(path1[i]==path2[j]) res=path1[i]; return res; }
idea:上述方法是先找到路径,再比较路径,其实可以边遍历边比较。如果节点为空则返回-1,如果当前节点是两者其中之一,则返回当前节点值,然后再依次遍历左子树和右子树,当左子树返回-1则表明在左子树没找到故返回右子树,反之当右子树返回-1则表明在右子树没找到故返回左子树,反之两个都找到了则表明最近公共祖先即为当前节点。
int lowestCommonAncestor(TreeNode* root, int o1, int o2) { // 该子树没找到返回-1 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; }