题目描述
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
示例
求解思路
从第一个root开始,分别遍历其左、右子树,记录左、右子树中含有要找的节点的个数l和r
- 若root就是p或q中的一个,直接返回root
- 若l=1,r=1,则最近公共祖先就为root
- 若l=2,则root = root.left,重复上述过程
- 若r=2,则root=root.right,重复上述过程
代码
执行用时:2725 ms, 在所有 Java 提交中击败了5.51%的用户
内存消耗:39.9 MB, 在所有 Java 提交中击败了96.74%的用户
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
while(root!=null){
if(root==p||root==q){
return root;
}
int l = search(root.left,p,q);
int r = search(root.right,p,q);
if(l==1&&r==1){
return root;
}
if(l==2){
root = root.left;
}
if(r==2){
root = root.right;
}
}
return null;
}
int search(TreeNode root, TreeNode p, TreeNode q){ //中序遍历
int num = 0;
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode tmp = root;
while(tmp!=null||!stack.empty()){
while(tmp!=null){
stack.push(tmp);
tmp = tmp.left;
}
if(tmp==null&&!stack.empty()){
tmp = stack.pop();
if(tmp==p||tmp==q){
num++;
}
tmp = tmp.right;
}
}
return num;
}
}
改进代码(太妙了,下次再做估计还是想不到)
执行用时:7 ms, 在所有 Java 提交中击败了99.89%的用户
内存消耗:40.7 MB, 在所有 Java 提交中击败了39.74%的用户
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null||root==p||root==q){
return root; //遍历到叶子节点时,这里直接返回null
}
TreeNode left = lowestCommonAncestor(root.left,p,q); //这里相当于前序遍历,但只要遍历到一个跟p或q相等的就不用继续往下遍历了,妙啊!!
TreeNode right = lowestCommonAncestor(root.right,p,q);
if(left==null&&right==null){ //左右子树皆为空
return null;
}
else if(left==null){ //左子树为空,则两个都在右子树中,同时由于只要等于p和q中的其中一个,就返回了,可以得出现在的right就是最近公共祖先(比较靠上的那个),因此返回right
return right;
}
else if(right==null){ //右子树为空,返回left,理由同上
return left;
}
return root; //左右子树都不为空,说明分布在两侧,那么root就是最近公共祖先
}
}