力扣
核心:后序遍历模型,每个父节点接收子节点的状态(是否含有p、q)并把这个状态依次向上传递,直到该结点满足祖先节点的条件,时间复杂度O(N)。
public class LowestCommonAncestor {
private TreeNode result;
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
dfs(root, p, q);
return result;
}
/**
* 当前root子树中是否找到p或q
*
* @param root 根节点
* @param p 节点p
* @param q 节点q
* @return true:找到p或q, false:未找到
*/
private boolean dfs(TreeNode root, TreeNode p, TreeNode q) {
// 如果已经找到答案,就不需要再遍历了,提前退出遍历(剪枝)
if (result != null) {
return false;
}
if (root == null) {
return false;
}
// p,q 是否在左子树
boolean inLeft = dfs(root.left, p, q);
// p,q 是否在右子树
boolean inRight = dfs(root.right, p, q);
// p,q 是否为当前节点
boolean inCurrent = root == p || root == q;
/**
* 1. 左右子树都找到了,证明当前root就是最近公共祖先
* 2. 如果当前节点为p,q中的一个,只要左子树或右子树有另一个节点,那么root就是最近公共祖先
*/
if ((inLeft && inRight) || (inCurrent && (inLeft || inRight))) {
result = root;
}
return inLeft || inRight || inCurrent;
}
}
自底向上分别从p,q遍历到根节点并且记录路径,如果存在公共祖先,那么p,q的路径必然相交,交点即为最近的公共祖先。
1. dfs 遍历整棵二叉树,使用哈希表,记录节点的父节点。
2.利用哈希表,自底向上遍历获取p, q的路径。
3.遍历两条路径,寻找交点。
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
// 节点value与父节点value哈希表
Map nodeToParentMap = new HashMap<>();
// 节点value与节点哈希表
Map valueToNodeMap = new HashMap<>();
// dfs 遍历树构建哈希表
dfsForLowestCommonAncestor(root, null, nodeToParentMap, valueToNodeMap);
// 获取路径
List pPathList = getNodePath(p, nodeToParentMap);
List qPathList = getNodePath(q, nodeToParentMap);
// 遍历路径获取交点
for (Integer nodeForPPath : pPathList) {
for (Integer nodeForQPath : qPathList) {
// 交点
if (nodeForPPath.equals(nodeForQPath)) {
return valueToNodeMap.get(nodeForPPath);
}
}
}
return null;
}
/**
* 利用哈希表自底向上获取节点路径
*
* @param node 当前节点
* @param nodeToParentMap key:节点value,value:父节点value
* @return 节点路径列表
*/
private List getNodePath(TreeNode node, Map nodeToParentMap) {
List pathList = new ArrayList<>();
Integer nodeValue = node.val;
pathList.add(nodeValue);
while (nodeToParentMap.get(nodeValue) != null) {
Integer parentNodeValue = nodeToParentMap.get(nodeValue);
pathList.add(parentNodeValue);
nodeValue = parentNodeValue;
}
return pathList;
}
/**
* dfs遍历
*
* @param node 当前节点
* @param parentNode 父节点
* @param nodeToParentMap 当前节点 -> 父节点
* @param valueToNodeMap 当前节点value -> node
*/
private void dfsForLowestCommonAncestor(TreeNode node, TreeNode parentNode, Map nodeToParentMap, Map valueToNodeMap) {
if (node == null) {
return;
}
dfsForLowestCommonAncestor(node.left, node, nodeToParentMap, valueToNodeMap);
if (parentNode != null) {
nodeToParentMap.put(node.val, parentNode.val);
}
valueToNodeMap.put(node.val, node);
dfsForLowestCommonAncestor(node.right, node, nodeToParentMap, valueToNodeMap);
}
时间复杂度:O(N^2)