最近公共祖先

#### [ 二叉搜索树的最近公共祖先](https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/) 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 [百度百科](https://baike.baidu.com/item/%E6%9C%80%E8%BF%91%E5%85%AC%E5%85%B1%E7%A5%96%E5%85%88/8918834?fr=aladdin)中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(**一个节点也可以是它自己的祖先**)。” 例如,给定如下二叉搜索树:  root = [6,2,8,0,4,7,9,null,null,3,5] ![](https://upload-images.jianshu.io/upload_images/23216847-3124dec94f0c4dbe.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) **示例 1:** >**输入:** root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8 **输出:** 6 **解释:** 节点 `2` 和节点 `8` 的最近公共祖先是 `6。` **示例 2:** >**输入:** root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4 **输出:** 2 **解释:** 节点 `2` 和节点 `4` 的最近公共祖先是 `2`, 因为根据定义最近公共祖先节点可以为节点本身 **说明:** * 所有节点的值都是唯一的 * p、q 为不同节点且均存在于给定的二叉搜索树中 **递归法** 由于所有节点的值都是唯一的 - p、q都比root小,那它们都在左子树中,去root.left找 - p、q都比root大,那它们都在右子树中,去root.right找 - p、q分布在root的两侧,root即为结果 ```java public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { if (p.val < root.val && q.val < root.val) { return lowestCommonAncestor(root.left, p, q); } else if (p.val > root.val && q.val > root.val) { return lowestCommonAncestor(root.right, p, q); } else { return root; } } ``` 时间复杂度 O(N): 其中 N 为二叉树节点数,二叉搜索树的层数最小为 logN (满二叉树),最大为 N (退化为链表) 空间复杂度 O(N) : 最差情况下,递归深度达到树的层数 N **迭代法** ```java public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { while (root != null) { if (p.val < root.val && q.val < root.val) { root = root.left; } else if (p.val > root.val && q.val > root.val) { root = root.right; } else { return root; } } return null; } ``` 时间复杂度O(n),空间复杂度O(1) #### [二叉树的最近公共祖先](https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/) 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 [百度百科](https://baike.baidu.com/item/%E6%9C%80%E8%BF%91%E5%85%AC%E5%85%B1%E7%A5%96%E5%85%88/8918834?fr=aladdin)中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(**一个节点也可以是它自己的祖先**)。” 例如,给定如下二叉树:  root = [3,5,1,6,2,0,8,null,null,7,4] ![](https://upload-images.jianshu.io/upload_images/23216847-e3d2017e110a0057.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) **示例 1:** >**输入:** root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1 **输出:** 3 **解释:** 节点 `5` 和节点 `1` 的最近公共祖先是节点 `3` **示例 2:** >**输入:** root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4 **输出:** 5 **解释:** 节点 `5` 和节点 `4` 的最近公共祖先是节点 `5`因为根据定义最近公共祖先节点可以为节点本身 **说明:** * 所有节点的值都是唯一的 * p、q 为不同节点且均存在于给定的二叉树中 **方法一:递归** ```java public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { if (root == null || root == p || root == q) { return root; } TreeNode left = lowestCommonAncestor(root.left, p, q);//找到p或q或null TreeNode right = lowestCommonAncestor(root.right, p, q); if (left == null) {//左子树中没有出现p、q,pq同时出现在右子树中,祖先为right return right; } if (right == null) { return left; } return root;//pq分布在左右子树,返回根 } ``` **方法二:存储父结点** - 先遍历二叉树,将所有结点对应的父节点存到map中 - 根据map向上遍历p,将p及其所有祖先加到set中 - 向上遍历q,如果set中存在q,说明它是p、q的公共祖先,由于是向上遍历的,第一个相同的即为最近的祖先 ```java private Map parent = new HashMap<>(); private Set set = new HashSet<>(); public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { dfs(root); while (p != null) { set.add(p); p = parent.get(p); } while (q != null) { if (set.contains(q)) { return q; } q = parent.get(q); } return null; } public void dfs(TreeNode root) { if (root.left != null) { parent.put(root.left, root); dfs(root.left); } if (root.right != null) { parent.put(root.right, root); dfs(root.right); } } ```

你可能感兴趣的:(最近公共祖先)