【算法】【面试级】Hot100 236. 二叉树的最近公共祖先
1. 递归
分析
遇到二叉树,递归是一个常见的思路。
构造一个辅助函数,返回boolean,代表这个节点root是否是p或q的祖先。
如果左子树返回true 且右子树也返回true,root就是p和q的祖先
左右子树只要一个返回true,并且root是p或者q,root也是p和q的祖先。
为什么不用区分到底是哪种情况呢,因为根本区分不了,辅助函数的对错就没有区分
左是对的,假设它是p的祖先,则root不可能是p,root那一项如果是true,只能是root是q
左是对的,假设它是p和q的公共祖先,那么它应该已经被填入答案了,右就不可能有p或q,root也不可能是p或q,root就不是答案了
算法
//主函数
//1. 调用dfs函数
//dfs函数
//1. 检查边界条件
//2. 递归
//3. 检查root是否是p和q的公共祖先,如果是存入ans
//4. 返回root是否是p或q的祖先
代码
public class Solution {
private TreeNode ans;
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
ans = root;
//调用dfs
dfs(root, p, q);
return ans;
}
private boolean dfs(TreeNode root, TreeNode p, TreeNode q){
//1. 边界条件处理
if(root == null){
return true;
}
//2. 递归 左与右
boolean lSon = dfs(root.left, p, q);
boolean rSon = dfs(root.right, p, q);
//3. 如果root是p和q的最近公共祖先 存入答案,再远的公共祖先不会被判定为true
if((lSon && rSon) || ((lSon || rSon) && (root.val == p.val || root.val == q.val)){
ans = root;
}
//4. 返回root是否是p或q的祖先
return lSon || rSon || root.val == p.val || root.val == q.val;
}
}
2. 遍历
分析
主函数
遍历p的祖先节点
标记为true
遍历q的祖先节点
遇到的第一个true就是答案
难点1 给定一个节点 找到父节点
采用HashMap,以节点的值为key,父节点为value
难点2 判断一个节点是否被访问过
采用HashSet
算法
//主函数
//1. 遍历p的祖先节点,都标记在HashSet visited里
//2. 遍历q的祖先节点,遇到第一个visited里有的结点则返回
//dfs 构建HashMap parent
//1. 递归
//2. 如果左子结点不为空,加入parent
//3. 如果右子结点不为空,加入parent
代码
public class Solution {
private Map<Integer, TreeNode> parent = new HashMap<>();
private Set<TreeNode> visited = new HashSet<>();
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
dfs(root);
//1. 遍历p的祖先节点,加入visited
while(p != null){
visited.add(p);
p = parent.get(p.val);
}
//2. 遍历q的祖先节点,如果某节点在visited中,直接返回
while(q != null){
if(visited.contains(q)){
return q;
}
q = parent.get(q.val);
}
return null;
}
private void dfs(TreeNode root){
//1. 左
if(root.left != null){
dfs(root.left);
parent.put(root.left.val, root);
}
//2. 右
if(root.right != null){
dfs(root.right);
parent.put(root.right.val, root);
}
}
}
浙公网安备 33010602011771号