Leetcode236.二叉树的最近公共祖先 Lowest Common Ancestor of a Binary Tree(Java)
##Tree##
二叉树的最近公共祖先
后续遍历就是天然的回溯法
采用后续遍历所有的结点,主要采用回溯的思想
- 递归函数的作用判断是否能找到结点
p
或q
,但由于还要寻找最近的公共祖先,因此需要返回TreeNode
- 递归出口设定为找到了
p
或q
,或者已经遍历完一条路径时,返回此时遍历的结点root
- 左子树不空时,递归遍历左子树,返回结果为
left
,右子树不空时,递归遍历右子树,返回结果为right
- 对于返回的
left
和right
- 若
left
和right
都为空,即要找的两结点p
和q
都不在正在遍历结点root
为根的树上,返回root
- 若
left
和right
都不为空,即要找的两结点p
和q
分别分布在正在遍历结点的root
的左子树和右子树上,此时root
就是最小公共祖先,返回root
- 若
left
和right
中只有一个非空,另一个为空值,有两种情况,可能p
和q
两个结点都分布在返回非空的一侧子树上,也可能p
或q
只有一个结点在非空的一侧子树上,两种情况都返回left
和right
中的非空值
- 若
时间复杂度: O(n)
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || root == p || root == q) return root;
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if (left != null && right != null) return root;
if (left != null) return left;
if (right != null) return right;
return null;
}
}
可以将问题拆分为在二叉树中找根节点到结点p
的路径,找根节点到节点q
的路径
找到两条路径后,再在其中找出最早的公共结点,参考Leetcode160,这里不再是链表,而是动态数组
时间复杂度: O(n)
class Solution {
Stack<TreeNode> sta = new Stack<>();
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
ArrayList<TreeNode> arr1 = new ArrayList<TreeNode>();
dfs(root, p, arr1);
ArrayList<TreeNode> arr2 = new ArrayList<TreeNode>();
dfs(root, q, arr2);
for (int i = arr1.size() - 1, j = arr2.size() - 1; i > 0 && j > 0; i--, j--) {
if (arr1.get(i).val == arr2.get(j).val && arr1.get(i - 1).val != arr2.get(j - 1).val) {
return arr1.get(i);
}
}
return arr1.size() > arr2.size() ? arr2.get(0) : arr1.get(0);
}
public boolean dfs(TreeNode root, TreeNode target, ArrayList<TreeNode> array) {
if (root == null) return false;
if (root.val == target.val) {
array.add(root);
return true;
}
if (dfs(root.left, target, array) || dfs(root.right, target, array)) {
array.add(root);
return true;
}
return false;
}
}