(基于评论区大佬的思路,该思路完爆官方的递归染色)
题目:
思路:
DFS遍历
用数组记录两个变量的父节点,然后找到公共父节点
class Solution {
Map<Integer, TreeNode> parent = new HashMap<Integer, TreeNode>();
Set<Integer> visited = new HashSet<Integer>();
public void dfs(TreeNode root) {
if (root.left != null) {
parent.put(root.left.val, root);
dfs(root.left);
}
if (root.right != null) {
parent.put(root.right.val, root);
dfs(root.right);
}
}
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
dfs(root);
while (p != null) {
visited.add(p.val);
p = parent.get(p.val);
}
while (q != null) {
if (visited.contains(q.val)) {
return q;
}
q = parent.get(q.val);
}
return null;
}
}
递归染色
由于大佬的代码思路和官方思路一致,只是极大的简化了代码,所以先来理解官方思路
官方题解的思路是对含有两个节点的路径进行标记,若一个节点满足公式((x == p || x == q) && (Flson || Frson)) || (Flson && Frson)
则就是最近父节点
最近父节点仅有两种可能:
- p在最近父节点左/右子树,q在最近父节点右/左子树,两个节点不在同一子树上
- p/q的子树包含q/p(包括q/p就是最近父节点的情况)
上方公式即各自对应两种情况
(Flson && Frson)代表可能性(1),即左子树包含节点,右子树也包含节点,则当前节点就为最近父节点
((x == p || x == q) && (Flson || Frson)) 当前节点为最近父节点,同时左/右子树包含另一个节点,则当前节点也是最近父节点
官方代码:
class Solution {
private TreeNode ans;
public Solution() {
this.ans = null;
}
private boolean dfs(TreeNode root, TreeNode p, TreeNode q) {
if (root == null) return false;
boolean lson = dfs(root.left, p, q);
boolean rson = dfs(root.right, p, q);
if ((lson && rson) || ((root.val == p.val || root.val == q.val) && (lson || rson))) {
ans = root;
}
return lson || rson || (root.val == p.val || root.val == q.val);
}
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
this.dfs(root, p, q);
return this.ans;
}
}
官方代码太过繁琐,即需要一个变量来记录答案,又需要用一个boolean类型来传递是否含有子节点.那么是否有一种办法传递一个变量来判断,最后的结果又是答案?
即包含目标节点的路径标记直接标记为目标节点,其余都为null,若左子树为null,则返回有可能包含目标节点的右子树,反之亦然.
仅有左右子树都被标记,则当前节点就是最近父节点,返回(可能性1)
最巧妙的是可能性(2),若一个目标节点在另一个目标节点的子树上,直接返回,就是答案
大佬代码:
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null || root == p || root == q)
{
return root;
}
TreeNode leftRoot = lowestCommonAncestor(root.left,p,q);
TreeNode rightRoot = lowestCommonAncestor(root.right,p,q);
if(leftRoot == null) return rightRoot;
if(rightRoot == null) return leftRoot;
return root;
}
}