链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree
注意这里的问题其实就告诉了做题的人,这里既没有父亲节点,也没有二叉搜索树的性质。
LCA的问题,一般来说就是几种套路
1 塑造父亲节点
一般来说,现确定有没有父节点的这个附加功能,如果有父节点,那么就是两个链表,寻找公共点的问题。
如果没有父亲节点这个附加功能,那么就要构造出一个子节点和父亲节点相关联的映射表来。
这个是万能的解,走过一遍,然后用个HashMap来做个子节点和父亲节点映射关系的map.
至于你遍历的时候用的是前中后序遍历,还是层序遍历,这个都无关紧要了。
public static TreeNode lowestCommonAncestorByFatherMap(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || p == root || q == root) {
return root;
}
if (p == null) {
return q;
}
if (q == null) {
return p;
}
Map<TreeNode, TreeNode> fatherMap = new HashMap<>();
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while (queue.size() > 0) {
int count = queue.size();
while (count > 0) {
TreeNode temp = queue.poll();
if (temp.left != null) {
fatherMap.put(temp.left, temp);
queue.offer(temp.left);
}
if (temp.right != null){
fatherMap.put(temp.right, temp);
queue.offer(temp.right);
}
count--;
}
}
HashSet<TreeNode> paths = new HashSet<>();
while (p != null) {
paths.add(p);
p = fatherMap.get(p);
}
TreeNode ans = null;
while (q != null ){
if (paths.contains(q)) {
ans = q;
break;
}
q = fatherMap.get(q);
}
return ans;
}
2 找路径法
这个方法其实不咋好,其实就是先遍历把所有的点给遍历了,然后按照中序遍历来存储点,放入list中。
然后寻找点的位置,然后把所有第一个点的位置给放到set中,然后在利用第二个做同样的操作。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
List<TreeNode> list = new ArrayList<>();
Set<TreeNode> pathP = new HashSet<TreeNode>();
TreeNode result = null;
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
allPath(root);
searchP(p);
searchQ(q);
return result;
}
public void searchP(TreeNode p) {
int indexP = list.indexOf(p);
TreeNode preNode = p;
pathP.add(p);
for (int i = indexP; i >= 0; --i) {
TreeNode tempNode = list.get(i);
if (tempNode.left == preNode || tempNode.right == preNode) {
pathP.add(tempNode);
preNode = tempNode;
}
}
}
public void searchQ(TreeNode q) {
int indexQ = list.indexOf(q);
TreeNode preNode = q;
for (int i = indexQ; i >= 0; --i) {
TreeNode tempNode = list.get(i);
if (tempNode == preNode || tempNode.left == preNode || tempNode.right == preNode) {
if (pathP.contains(tempNode)) {
result = tempNode;
return;
}
preNode = tempNode;
}
}
result = q;
}
public void allPath(TreeNode node) {
if (node == null) {
return;
}
list.add(node);
allPath(node.left);
allPath(node.right);
}
}
3递归找节点
这个比较难以想到,首先就是你精通后序遍历了,先找左边的那个子节点他爹节点,然后找右边的节点的他爹的节点,然后两个比较一下子,看看是不是左右的两个节点都存在,都存在就返回root。
如分别左右节点都找到了,那么当前的根节点肯定就是结果了。
public TreeNode betterLowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || p == root || q == root) {
return root;
}
TreeNode left = betterLowestCommonAncestor(root.left, p, q);
TreeNode right = betterLowestCommonAncestor(root.right, p, q);
if (left != null && right != null) {
return root;
}
if (left != null) {
return left;
}
if (right != null) {
return right;
}
return null;
}