最低公共祖先问题(LCA) 举一反三
2017-09-13 18:43
309 查看
算法总是美的,充满着magic.
下面是一个简单的复杂度为 O(n) 的算法,解决LCA问题
1) 找到从根到n1的路径,并存储在一个向量或数组中。
2)找到从根到n2的路径,并存储在一个向量或数组中。
3) 遍历这两条路径,直到遇到一个不同的节点,则前面的那个即为最低公共祖先.
1.2 代码
1.1 思路
从root开始遍历,如果n1和n2中的任一个和root匹配,那么root就是LCA。 如果都不匹配,则分别递归左、右子树,如果有一个 key(n1或n2)出现在左子树,并且另一个key(n1或n2)出现在右子树,则root就是LCA. 如果两个key都出现在左子树,则说明LCA在左子树中,否则在右子树。
1.2 代码
1.1 思路
思路同上述常规解法. 相当找三个链表的最后一个公共节点.
1.2 代码
直接上代码:
一.前言
给定一棵树,同时给出树中的两个结点或者两个以上节点,求它们的最低公共祖先。这就是常见的LCA(Lowest Common Ancestor )问题。二.两个节点的LCA问题
常规解法
1.1 思路下面是一个简单的复杂度为 O(n) 的算法,解决LCA问题
1) 找到从根到n1的路径,并存储在一个向量或数组中。
2)找到从根到n2的路径,并存储在一个向量或数组中。
3) 遍历这两条路径,直到遇到一个不同的节点,则前面的那个即为最低公共祖先.
1.2 代码
//遍历两次,时间复杂度为O(n) private static int findLCA(BinaryTree root, int key1, int key2) { if (root == null) { return -1; } List<Integer> path1 = new ArrayList<>(); List<Integer> path2 = new ArrayList<>(); boolean found1 = findPath(root,path1,key1); boolean found2 = findPath(root,path2,key2); int ans = 0; if (found1 && found2) { for (int i = 0; i < path1.size(); i++) { if (path1.get(i) != path2.get(i)) { break; }else { ans = path1.get(i); } } return ans; } return -1; } /** * @category 从根节点找到一条到指点数的路径. * @param root 二叉树根节点 * @param path 存储根节点到key的路径 * @param key 要查找的数 * @return 若路径存在则返回true,否则,false. * */ private static boolean findPath(BinaryTree root, List<Integer> path, int key) { if (root == null) { return false; } path.add(root.value); if (root.value == key) { return true; } boolean find = (findPath(root.left, path, key)||findPath(root.right, path, key)); if (find) { return true; } path.remove(path.indexOf(root.value)); return false; }
优化解法
只遍历一次1.1 思路
从root开始遍历,如果n1和n2中的任一个和root匹配,那么root就是LCA。 如果都不匹配,则分别递归左、右子树,如果有一个 key(n1或n2)出现在左子树,并且另一个key(n1或n2)出现在右子树,则root就是LCA. 如果两个key都出现在左子树,则说明LCA在左子树中,否则在右子树。
1.2 代码
/** * 从root节点向下遍历,若root.value等于任一要查找的值,则root为祖先节点, * 如果都不匹配,则遍历左子树和右子树,如果一个key出现在左子树,一个出现在右子树,则root为祖先节点, * 如果两个都出现在左子树,则说明LCA在左子树,否则在右子树. * @param root 二叉树根节点 * @param key1,key2 要查找的数 * @return 公共祖先节点 */ private static BinaryTree findLCA(BinaryTree root, int key1, int key2) { if (root == null) { return null; } if (root.value == key1 || root.value == key2) { return root; } BinaryTree left = findLCA(root.left, key1, key2); BinaryTree right = findLCA(root.right, key1, key2); if (left != null && right != null) { return root; } return (left !=null)?left:right; }
三.三个节点的LCA问题
题目如题.1.1 思路
思路同上述常规解法. 相当找三个链表的最后一个公共节点.
1.2 代码
/** * @param root 二叉树根节点 * @param key1,key2,key3 要查找的数 * @return 公共祖先节点 */ private static int findLCA(BinaryTree root, int key1, int key2, int key3) { if (root == null) { return -1; } List<Integer> path1 = new ArrayList<>(); List<Integer> path2 = new ArrayList<>(); List<Integer> path3 = new ArrayList<>(); boolean found1 = findPath(root,path1,key1); boolean found2 = findPath(root,path2,key2); boolean found3 = findPath(root,path3,key3); int ans = 0; if (found1 && found2 && found3) { int index = 0; while(index<path1.size()){ if (path1.get(index)==path2.get(index)&&path1.get(index)==path3.get(index)) { ans = path1.get(index); index++; }else { break; } } return ans; } return -1; } private static boolean findPath(BinaryTree root, List<Integer> path, int key) { if (root == null) { return false; } path.add(root.value); if (root.value == key) { return true; } boolean found = (findPath(root.left, path, key)||findPath(root.right, path, key)); if (found) { return true; } path.remove(path.indexOf(root.value)); return false; }
四.三个节点的LCA问题
给定一满二叉排序树,节点从1-(2^k-1),给出三个数a,b,c;找出它们的最低公共祖先. (腾讯题)直接上代码:
import java.util.Scanner; /** * LCA 问题: 满二叉排序树中三个节点的最低公共祖先 * @author dingding * @version 9-13 */ public class BT_NoParentPtr_Solution4 { public static void main(String[] args) { Scanner cin = new Scanner(System.in); while(cin.hasNext()){ int k = cin.nextInt(); int a = cin.nextInt(); int b = cin.nextInt(); int c = cin.nextInt(); int result = findLCA(a,b,c,1,(2<<k)-1); System.out.println(result); } } /** * 若根节点的值为m,若存在(a-m)(b-m)<0 || (a-m)(c-m)<0 || (b-m)(c-m)<0,则节点m 为最低祖先. * @param a,b,c 查找的三个数 * @param left 数组最左边的值,right 数组最右边. (数组为二叉排序数组) * @return 公共祖先节点 */ private static int findLCA(int a, int b, int c, int left, int right) { int m = left+(right-left)/2; if (((a-m)*(b-m)<=0) || ((a-m)*(c-m)<=0) || ((b-m)*(c-m)<=0)) { return m; }else if(a>m){ //不在根节点,a>m必有一节点在右子树,搜索右侧. return findLCA(a, b, c, m+1, right); }else { return findLCA(a, b, c, left, m-1); } } }
参考文献
寻找二叉树两个节点的最低公共祖先相关文章推荐
- 寻找二叉树中的最低公共祖先结点----LCA(Lowest Common Ancestor )问题(递归)
- Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)
- LCA树两个节点最低公共祖先
- 最近公共祖先(LCA)和RMQ问题
- LCA问题(最近公共祖先问题)+ RMQ问题
- 1 数据结构类-最近公共祖先LCA问题
- 树的公共祖先问题LCA
- 【Leetcode】查找二叉树中任意结点的最近公共祖先(LCA问题)
- LCA(最近公共祖先)问题的离线算法
- POJ1330Nearest Common Ancestors最近公共祖先LCA问题
- 最近公共祖先LCA问题
- 树的公共祖先问题LCA
- LCA问题(最近公共祖先问题)+ RMQ问题
- 1 数据结构类-最近公共祖先LCA问题
- 二叉搜索树(BST)的最近公共祖先(LCA)问题(Lowest Common Ancestor of a Binary Tree)
- 【Leetcode】查找二叉树中任意结点的最近公共祖先(LCA问题)
- hdu2596LCA公共祖先问题(离线Tarjan算法)
- 面试题50 树中两个节点的最低公共祖先LCA(Lowest Common Ancestor )
- 面试经典(5)--二叉树最低公共祖先LCA
- 1 数据结构类-最近公共祖先LCA问题