前言
此树非二叉排序树,无法利用有序条件。
不能在递归过程中做事情,在回溯时来判断p、q是否来自左右节点。遇到p、q就返回其节点,然后在右子树找是否有另一个节点,存在情况如下。
1)左右都找到相应节点,则返回root。
2)都在左,从上到下找到一个节点,就返回左边较上的节点作为公共节点。
3)都在右,从上到下找到一个节点,就返回右边较上的节点作为公共节点。
一、回溯
//剑指offer68—II二叉树的最近公共祖先
public TreeNode lowestCommonAncestor3(TreeNode root, TreeNode p, TreeNode q) {
//返回p或者q节点,利用回溯的过程进行判断,p,q在数的左端还是右端,如果是左端,返回左;右端返回右;左右返回root
if(root == null)
return null;
if(root == p || root == q)
return root;
TreeNode left = lowestCommonAncestor3(root.left,p,q);
TreeNode right = lowestCommonAncestor3(root.right,p,q);
if(left != null && right != null){
return root;
}
if(left != null)
return left;
if(right != null)
return right;
return null;
}
二、回溯+剪枝
当出现第一种情况,左右节点都寻找到相应的p、q时,则再次递归下去就直接遇到出口,从而进行剪枝。
1、剪枝
//剑指offer68—II二叉树的最近公共祖先+剪枝
boolean isFind = false;
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
//返回p或者q节点,利用回溯的过程进行判断,p,q在数的左端还是右端,如果是左端,返回左;右端返回右;左右返回root
if(root == null)
return null;
if(root == p || root == q)
return root;
//设置标识,进行剪枝(提前return null)
if(isFind)
return null;
TreeNode left = lowestCommonAncestor(root.left,p,q);
TreeNode right = lowestCommonAncestor(root.right,p,q);
if(left != null && right != null){
//一旦寻找到真正的最近公共祖先,就设置已找到条件,为剪枝做准备。
isFind = true;
return root;
}
if(left != null)
return left;
if(right != null)
return right;
return null;
}
总结
1)掌握四种遍历方式
2)利用好回溯
3)可以提前返回就不需要进行无意义的递归,需剪枝。