剑指offer(java):求树中两个结点的最低公共祖先
2016-08-09 00:00
190 查看
题目:
树中两个节点的最低公共祖先。
最近公共祖先简称LCA(Lowest Common Ancestor),所谓LCA,是当给定一个有根树T时,对于任意两个结点u、v,找到一个离根最远的结点x,使得x同时是u和v的祖先,x 便是u、v的最近公共祖先。
思路一:
输入两个树节点,求他们的最低公共祖先,
——如果是二叉树,而且是二叉搜索树,那么是可以找到公共节点的。
二叉搜索树都是排序过的,位于左子树的节点都比父节点小,而位于右子树上面的节点都比父节点大。
如果当前节点的值比两个结点 的值都大,那么最低的共同的父节点一定是在当前节点的左子树中,于是下一步遍历当前节点的左子节点。
如果当前节点的值比两个结点的值都小,那么最低的共同的父节点一定是在当前节点的右子树中,于是下一步遍历当前节点的右子节点。
这样从上到下,找到的第一个在两个输入结点的值之间的节点,就是最低的公共祖先。
package cglib;
class TreeNode {
int data;
TreeNode left;
TreeNode right;
}
public class List1
{
public static TreeNode getLastCommonParent(TreeNode root,TreeNode a,TreeNode b)
{
if (root==null || a==null || b==null)
return null;
while (root != null) {
if (root.data > a.data && root.data > b.data )
root = root.left;
else if (root.data < a.data && root.data < b.data)
root = root.right;
else
return root;
}
return null;
}
public static void main(String args[]){
TreeNode n1 = new TreeNode();
TreeNode n2 = new TreeNode();
TreeNode n3 = new TreeNode();
TreeNode n4 = new TreeNode();
TreeNode n5 = new TreeNode();
TreeNode n6 = new TreeNode();
TreeNode n7 = new TreeNode();
n1.left=n2;
n1.right=n3;
n2.left=n4;
n2.right=n5;
n3.left=n6;
n3.right=n7;
n1.data=10;
n2.data=8;
n3.data=13;
n4.data=4;
n5.data=9;
n6.data=12;
n7.data=17;
// 搜索二叉树
// 10
// / \
// 8 13
// / \ / \
// 4 9 12 17
System.out.println(n1.data);
System.out.println(n6.data);
System.out.println(n7.data);
TreeNode parent=getLastCommonParent(n1, n6, n7);
System.out.println(parent.data);
}
}
输出:
10
12
17
13
思路二:
如果这棵树是普通的树,而且树中结点没有指向父结点的指针,解法如下:
思路三:
我们可以用深度优先搜索,从叶子节点向上,标记子树中出现目标节点的情况。如果子树中有目标 节点,标记为那个目标节点,如果没有,标记为null。显然,如果左子树、右子树都有标记,说明就已经找到最小公共祖先了。如果在根节点为p的左右子树中 找p、q的公共祖先,则必定是p本身。
换个角度,可以这么想:如果一个节点左子树有两个目标节点中的一个,右子树没有,那这个节点 肯定不是最小公共祖先。如果一个节点右子树有两个目标节点中的一个,左子树没有,那这个节点肯定也不是最小公共祖先。只有一个节点正好左子树有,右子树也 有的时候,才是最小公共祖先。
package cglib;
class TreeNode {
int data;
TreeNode left;
TreeNode right;
}
public class List1
{
//两个节点的最低公共祖先,参数为两个节点
public static TreeNode getLastCommonParent(TreeNode root,TreeNode a,TreeNode b)
{
//发现目标节点则通过返回值标记该子树发现了某个目标结点
//如果在根节点为a的左右子树中找a、b的公共祖先,则必定是a本身。
//同理,如果在根节点为b的左右子树中找a、b的公共祖先,则必定是b本身。
if (root == null || root == a || root == b)
return root;
//查看左子树中是否有目标结点,没有为null
TreeNode left = getLastCommonParent(root.left, a, b);
//查看右子树是否有目标节点,没有为null
TreeNode right = getLastCommonParent(root.right, a, b);
//都不为空,说明左右子树都有目标结点,则公共祖先就是本身
if (left != null&&right != null)
return root;
//如果发现了目标节点,则继续向上标记为该目标节点
return left == null ? right : left;
}
public static void main(String args[]){
TreeNode n1 = new TreeNode();
TreeNode n2 = new TreeNode();
TreeNode n3 = new TreeNode();
TreeNode n4 = new TreeNode();
TreeNode n5 = new TreeNode();
TreeNode n6 = new TreeNode();
TreeNode n7 = new TreeNode();
n1.left=n2;
n1.right=n3;
n2.left=n4;
n2.right=n5;
n3.left=n6;
n3.right=n7;
n1.data=1;
n2.data=2;
n3.data=3;
n4.data=4;
n5.data=5;
n6.data=6;
n7.data=7;
// 搜索二叉树
// 1
// / \
// 2 3
// / \ / \
// 4 5 6 7
System.out.println(n1.data);
System.out.println(n6.data);
System.out.println(n7.data);
TreeNode parent=getLastCommonParent(n1, n6, n7);
System.out.println(parent.data);
}
}
输出:
1
6
7
3
以上解法需要对同一个结点重复遍历很多次,效率较低,如果允许使用辅助内存,则可以有效率更高的方法,解法如下:
package cglib;
import java.util.Stack;
class TreeNode {
int data;
TreeNode left;
TreeNode right;
}
public class List1
{
public static TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q){
Stack<TreeNode> stackp = new Stack<TreeNode>();
Stack<TreeNode> stackq = new Stack<TreeNode>();
getPath(root, p, stackp);
getPath(root, q, stackq);
return lowestCommonAncestor(stackp, stackq);
}
private static TreeNode lowestCommonAncestor(Stack<TreeNode> stackp, Stack<TreeNode> stackq) {
TreeNode target = null;
while (!stackp.isEmpty() && !stackq.isEmpty() && stackp.peek() == stackq.peek())
{
target = stackp.peek();
stackp.pop();
stackq.pop();
}
return target;
}
private static boolean getPath(TreeNode root, TreeNode p, Stack<TreeNode> stackp) {
// TODO Auto-generated method stub
if (root == null)
return false;
if (root == p)
{
stackp.push(root);
return true;
}
else
{
if (getPath(root.left, p, stackp) || getPath(root.right, p, stackp))
{
stackp.push(root);
return true;
}
}
return false;
}
/***
*
* 这个代码在实现过程中,是当找到给定节点的时候才将路径依次压入stack中的,
* 也就是说,两个stack的栈顶都是存放着root节点。
* 因此,此时就应该找两条路径分离开之前的最后一个节点,
* 此节点就是所求的最低公共祖先。
* @param args
*/
public static void main(String args[]){
TreeNode n1 = new TreeNode();
TreeNode n2 = new TreeNode();
TreeNode n3 = new TreeNode();
TreeNode n4 = new TreeNode();
TreeNode n5 = new TreeNode();
TreeNode n6 = new TreeNode();
TreeNode n7 = new TreeNode();
n1.left=n2;
n1.right=n3;
n2.left=n4;
n2.right=n5;
n3.left=n6;
n3.right=n7;
n1.data=1;
n2.data=2;
n3.data=3;
n4.data=4;
n5.data=5;
n6.data=6;
n7.data=7;
// 搜索二叉树
// 1
// / \
// 2 3
// / \ / \
// 4 5 6 7
System.out.println(n1.data);
System.out.println(n6.data);
System.out.println(n7.data);
TreeNode parent=lowestCommonAncestor(n1, n6, n7);
System.out.println(parent.data);
}
}
输出:
1
6
7
3
树中两个节点的最低公共祖先。
最近公共祖先简称LCA(Lowest Common Ancestor),所谓LCA,是当给定一个有根树T时,对于任意两个结点u、v,找到一个离根最远的结点x,使得x同时是u和v的祖先,x 便是u、v的最近公共祖先。
思路一:
输入两个树节点,求他们的最低公共祖先,
——如果是二叉树,而且是二叉搜索树,那么是可以找到公共节点的。
二叉搜索树都是排序过的,位于左子树的节点都比父节点小,而位于右子树上面的节点都比父节点大。
如果当前节点的值比两个结点 的值都大,那么最低的共同的父节点一定是在当前节点的左子树中,于是下一步遍历当前节点的左子节点。
如果当前节点的值比两个结点的值都小,那么最低的共同的父节点一定是在当前节点的右子树中,于是下一步遍历当前节点的右子节点。
这样从上到下,找到的第一个在两个输入结点的值之间的节点,就是最低的公共祖先。
package cglib;
class TreeNode {
int data;
TreeNode left;
TreeNode right;
}
public class List1
{
public static TreeNode getLastCommonParent(TreeNode root,TreeNode a,TreeNode b)
{
if (root==null || a==null || b==null)
return null;
while (root != null) {
if (root.data > a.data && root.data > b.data )
root = root.left;
else if (root.data < a.data && root.data < b.data)
root = root.right;
else
return root;
}
return null;
}
public static void main(String args[]){
TreeNode n1 = new TreeNode();
TreeNode n2 = new TreeNode();
TreeNode n3 = new TreeNode();
TreeNode n4 = new TreeNode();
TreeNode n5 = new TreeNode();
TreeNode n6 = new TreeNode();
TreeNode n7 = new TreeNode();
n1.left=n2;
n1.right=n3;
n2.left=n4;
n2.right=n5;
n3.left=n6;
n3.right=n7;
n1.data=10;
n2.data=8;
n3.data=13;
n4.data=4;
n5.data=9;
n6.data=12;
n7.data=17;
// 搜索二叉树
// 10
// / \
// 8 13
// / \ / \
// 4 9 12 17
System.out.println(n1.data);
System.out.println(n6.data);
System.out.println(n7.data);
TreeNode parent=getLastCommonParent(n1, n6, n7);
System.out.println(parent.data);
}
}
输出:
10
12
17
13
思路二:
如果这棵树是普通的树,而且树中结点没有指向父结点的指针,解法如下:
思路三:
我们可以用深度优先搜索,从叶子节点向上,标记子树中出现目标节点的情况。如果子树中有目标 节点,标记为那个目标节点,如果没有,标记为null。显然,如果左子树、右子树都有标记,说明就已经找到最小公共祖先了。如果在根节点为p的左右子树中 找p、q的公共祖先,则必定是p本身。
换个角度,可以这么想:如果一个节点左子树有两个目标节点中的一个,右子树没有,那这个节点 肯定不是最小公共祖先。如果一个节点右子树有两个目标节点中的一个,左子树没有,那这个节点肯定也不是最小公共祖先。只有一个节点正好左子树有,右子树也 有的时候,才是最小公共祖先。
package cglib;
class TreeNode {
int data;
TreeNode left;
TreeNode right;
}
public class List1
{
//两个节点的最低公共祖先,参数为两个节点
public static TreeNode getLastCommonParent(TreeNode root,TreeNode a,TreeNode b)
{
//发现目标节点则通过返回值标记该子树发现了某个目标结点
//如果在根节点为a的左右子树中找a、b的公共祖先,则必定是a本身。
//同理,如果在根节点为b的左右子树中找a、b的公共祖先,则必定是b本身。
if (root == null || root == a || root == b)
return root;
//查看左子树中是否有目标结点,没有为null
TreeNode left = getLastCommonParent(root.left, a, b);
//查看右子树是否有目标节点,没有为null
TreeNode right = getLastCommonParent(root.right, a, b);
//都不为空,说明左右子树都有目标结点,则公共祖先就是本身
if (left != null&&right != null)
return root;
//如果发现了目标节点,则继续向上标记为该目标节点
return left == null ? right : left;
}
public static void main(String args[]){
TreeNode n1 = new TreeNode();
TreeNode n2 = new TreeNode();
TreeNode n3 = new TreeNode();
TreeNode n4 = new TreeNode();
TreeNode n5 = new TreeNode();
TreeNode n6 = new TreeNode();
TreeNode n7 = new TreeNode();
n1.left=n2;
n1.right=n3;
n2.left=n4;
n2.right=n5;
n3.left=n6;
n3.right=n7;
n1.data=1;
n2.data=2;
n3.data=3;
n4.data=4;
n5.data=5;
n6.data=6;
n7.data=7;
// 搜索二叉树
// 1
// / \
// 2 3
// / \ / \
// 4 5 6 7
System.out.println(n1.data);
System.out.println(n6.data);
System.out.println(n7.data);
TreeNode parent=getLastCommonParent(n1, n6, n7);
System.out.println(parent.data);
}
}
输出:
1
6
7
3
以上解法需要对同一个结点重复遍历很多次,效率较低,如果允许使用辅助内存,则可以有效率更高的方法,解法如下:
package cglib;
import java.util.Stack;
class TreeNode {
int data;
TreeNode left;
TreeNode right;
}
public class List1
{
public static TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q){
Stack<TreeNode> stackp = new Stack<TreeNode>();
Stack<TreeNode> stackq = new Stack<TreeNode>();
getPath(root, p, stackp);
getPath(root, q, stackq);
return lowestCommonAncestor(stackp, stackq);
}
private static TreeNode lowestCommonAncestor(Stack<TreeNode> stackp, Stack<TreeNode> stackq) {
TreeNode target = null;
while (!stackp.isEmpty() && !stackq.isEmpty() && stackp.peek() == stackq.peek())
{
target = stackp.peek();
stackp.pop();
stackq.pop();
}
return target;
}
private static boolean getPath(TreeNode root, TreeNode p, Stack<TreeNode> stackp) {
// TODO Auto-generated method stub
if (root == null)
return false;
if (root == p)
{
stackp.push(root);
return true;
}
else
{
if (getPath(root.left, p, stackp) || getPath(root.right, p, stackp))
{
stackp.push(root);
return true;
}
}
return false;
}
/***
*
* 这个代码在实现过程中,是当找到给定节点的时候才将路径依次压入stack中的,
* 也就是说,两个stack的栈顶都是存放着root节点。
* 因此,此时就应该找两条路径分离开之前的最后一个节点,
* 此节点就是所求的最低公共祖先。
* @param args
*/
public static void main(String args[]){
TreeNode n1 = new TreeNode();
TreeNode n2 = new TreeNode();
TreeNode n3 = new TreeNode();
TreeNode n4 = new TreeNode();
TreeNode n5 = new TreeNode();
TreeNode n6 = new TreeNode();
TreeNode n7 = new TreeNode();
n1.left=n2;
n1.right=n3;
n2.left=n4;
n2.right=n5;
n3.left=n6;
n3.right=n7;
n1.data=1;
n2.data=2;
n3.data=3;
n4.data=4;
n5.data=5;
n6.data=6;
n7.data=7;
// 搜索二叉树
// 1
// / \
// 2 3
// / \ / \
// 4 5 6 7
System.out.println(n1.data);
System.out.println(n6.data);
System.out.println(n7.data);
TreeNode parent=lowestCommonAncestor(n1, n6, n7);
System.out.println(parent.data);
}
}
输出:
1
6
7
3
相关文章推荐
- 树中两个结点的最低公共祖先--java
- 《剑指offer》刷题笔记(综合):树中两个结点的最低公共祖先
- 剑指offer-面试题50-树中两个结点的最低公共祖先
- 《剑指Offer》学习笔记--面试题50:树中两个结点的最低公共祖先
- 剑指Offer - 九度1509 - 树中两个结点的最低公共祖先
- 《剑指offer》树中两个结点的最低公共祖先
- (剑指Offer)面试题50:树中两个结点的最低公共祖先
- 剑指offer面试题:求树中两个结点的最低公共祖先
- 剑指offer 面试题50 树中两个结点的最低公共祖先
- 《剑指offer》:[50]树中两个结点的最低公共祖先结点
- 《剑指offer》面试题50 树中两个结点的最低公共祖先
- 【九度】题目1509:树中两个结点的最低公共祖先
- 二叉树两个结点的最低公共祖先
- 树中两个结点的最低公共祖先
- 九度:题目1509:树中两个结点的最低公共祖先
- 题目1509:树中两个结点的最低公共祖先
- 有一个1亿结点的树,已知两个结点, 求它们的最低公共祖先!
- 九度:题目1509:树中两个结点的最低公共祖先
- 二叉树两个结点的最低公共祖先
- 树中两个结点的最低公共祖先