题目:输入两个树节点,求它们的最低公共祖先。
普通的树:
1、我们使用两个LinkedList依次记录从根节点到两个给定节点的路径
2、得到路径后,我们对两个路径进行比较,最后一个相等的节点即为所求(添加与取得顺序相反,所以最后一个为最低公共节点)
public TreeNode getLastCommonParent(TreeNode root, TreeNode p1, TreeNode p2) {
if (root == null || p1 == null || p2 == null) return null;
LinkedList<TreeNode> path1 = new LinkedList<>();
LinkedList<TreeNode> path2 = new LinkedList<>();
LinkedList<TreeNode> tem = new LinkedList<>();
getNodePath(root, p1, tem, path1);
getNodePath(root, p2, tem, path2);
if (path1.size() <= 0 || path2.size() <= 0) return null;
return getCommon(path1, path2);
}
// 比较两个path,得到最后一个相同节点,即我们的目标值
private TreeNode getCommon(LinkedList<TreeNode> path1, LinkedList<TreeNode> path2) {
TreeNode temNode = null;
for (int i = 0; i < path1.size(); i++) {
if (path1.get(i) != path2.get(i)) {
break;
}
temNode = path1.get(i);
}
return temNode;
}
// 获取
private void getNodePath(TreeNode root, TreeNode targeNode, LinkedList<TreeNode> tem, LinkedList<TreeNode> path) {
if (root == targeNode) {
return;
}
tem.add(root);
List<TreeNode> children = root.children; // 获取左右两个子节点,可能只存在一个,或者0个
for (TreeNode node : children) {
if (node == targeNode) {
path.addAll(tem);
break;
}
getNodePath(node, targeNode, tem, path);
}
tem.removeLast(); // 避免重复添加,删除掉(因为递归的性质,到达底层时,回溯时依次删除)
}
public class TreeNode {
public List<TreeNode> children = new ArrayList<>();
int val;
TreeNode(int x) {
val = x;
}
}
// 测试数据
val n1 = TreeNode(1)
val n2 = TreeNode(2)
val n3 = TreeNode(3)
val n4 = TreeNode(4)
val n5 = TreeNode(5)
val n6 = TreeNode(6)
val n7 = TreeNode(7)
val n8 = TreeNode(8)
val n9 = TreeNode(9)
val n10 = TreeNode(10)
n1.children.add(n2)
n1.children.add(n3)
n2.children.add(n4)
n4.children.add(n6)
n4.children.add(n7)
n3.children.add(n5)
n5.children.add(n8)
n5.children.add(n9)
n5.children.add(n10)
时间复杂度:O(n)
空间复杂度:O(logn)
其实还有另外的情况:如该树为普通二叉树
/**
* 递归,找到两个目标节点
* @param root
* @param left1
* @param right1
* @return
*/
public TreeNode getLastCommonParent2(TreeNode root,TreeNode left1,TreeNode right1){
if(root==null||root==left1||root==right1) {
return root;
}
// 递归是一个大过程,回溯时,左子树的右小枝也被算作大枝中的左枝
TreeNode left = getLastCommonParent2(root.left,left1,right1);
TreeNode right = getLastCommonParent2(root.right,left1,right1);
// 左节点为null说明根节点在右子树中或不存在,右节点为null说明根节点在左子树中或不存在,两个都不为null说明root就为目标值
return left==null?right:right==null?left:root;
// 等同于
// if(left==null) {
// return right;
// }else {
// if(right==null) {
// return left;
// }else {
// return root;
// }
// }
}
二叉搜索树:
若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值。利用此特性遍历递归即可。
public TreeNode getLowestCommonParentBST(TreeNode root,TreeNode node1,TreeNode node2) {
while(true) {
if(root==null)
return root;
if(root.val<node1.val && root.val<node2.val)
root=root.right;
else if(root.val>node1.val && root.val>node2.val)
root=root.left;
else
return root;
}
}