> 文章列表 > Leetcode 236. 二叉树的最近公共祖先

Leetcode 236. 二叉树的最近公共祖先

Leetcode 236. 二叉树的最近公共祖先

题目:
   给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
   百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
   树中节点数目在范围 [2, 105] 内。
   -109 <= Node.val <= 109
   所有 Node.val 互不相同 。
   p != q
   p 和 q 均存在于给定的二叉树中。

解法:
   类似前/中/后序方式递归遍历二叉树,左递归上方代表该课子树还未遍历,左递归与右递归中间代表遍历完左子树回溯,右递归下方代表左右子树都遍历完成处理,
  
   子树未遍历时,如果根节点就是 p 节点,则该子树无需遍历,回溯返回该节点即可,
   1. q 是它孩子则返回的是子树最近公共祖先,
   2. q 不是孩子则返回 p 节点就往其他方向找(q 和 p 互换),
  
   左右子树遍历后,分情况返回节点
   1. 如果左右子树均返回了节点,即 p 和 q 分别在左右子树,根节点就一定是最近公共祖先,返回根节点
   2. 如果一颗子树返回节点,那它一定是 p 或 q 或最近公共祖先(深度更大时出现的 1 那种情况),返回那个节点,有三种可能,
      要么该子树只存在 p 或者 q,那个节点就是 p 或者 q,
      要么 q 是 p 孩子节点,那个节点就是 p(q 和 p 互换),
     要么返回的就是最近公共祖先,
      都可以返回该节点继续回溯,
   3. 如果左右子树均没有返回节点(null),则该子树没有 p 或 q,返回 null
  
代码:

public class LowestCommonAncestor {public static void main(String[] args) {LowestCommonAncestor lowestCommonAncestor = new LowestCommonAncestor();while (true) {List<Integer> treeList = AlgorithmUtils.systemInList();TreeNode p = new TreeNode(AlgorithmUtils.systemInNumberInt());TreeNode q = new TreeNode(AlgorithmUtils.systemInNumberInt());// 建树TreeNode root = lowestCommonAncestor.createTree(treeList);System.out.println(root);TreeNode ancestorNode = lowestCommonAncestor.solution(root, p, q);System.out.println(ancestorNode.val);}}/* 通过 List 建树,数组是树的层序方式,如果父节点存在、但子节点存在零个或一个则使用 null 表示*/private TreeNode createTree(List<Integer> treeList) {if (CollectionUtils.isEmpty(treeList)) {return null;}TreeNode root = new TreeNode(treeList.get(0));Queue<TreeNode> treeNodeQueue = new ConcurrentLinkedQueue<>();treeNodeQueue.add(root);for (int i = 1; i < treeList.size(); i += 2) {TreeNode nowNode = treeNodeQueue.poll();if (treeList.get(i) != null) {nowNode.left = new TreeNode(treeList.get(i));treeNodeQueue.add(nowNode.left);}if (i + 1 < treeList.size() && treeList.get(i + 1) != null) {nowNode.right = new TreeNode(treeList.get(i + 1));treeNodeQueue.add(nowNode.right);}}return root;}private TreeNode solution(TreeNode root, TreeNode p, TreeNode q) {if (root == null) {return null;}return getAncestor(root, p ,q);}/* 最近公共祖先核心:类似前/中/后序方式递归遍历二叉树,* 左递归上方代表该课子树还未遍历,左递归与右递归中间代表遍历完左子树回溯,右递归下方代表左右子树都遍历完成处理,* 子树未遍历时,如果根节点就是 p 节点,则该子树无需遍历,回溯返回该节点即可,*  1. q 是它孩子则返回的是子树最近公共祖先,*  2. q 不是孩子则返回 p 节点就往其他方向找(q 和 p 互换),* 左右子树遍历后,分情况返回节点*  1. 如果左右子树均返回了节点,即 p 和 q 分别在左右子树,根节点就一定是最近公共祖先,返回根节点*  2. 如果一颗子树返回节点,那它一定是 p 或 q 或最近公共祖先(深度更大时出现的 1 那种情况),返回那个节点,有三种可能,*      要么该子树只存在 p 或者 q,那个节点就是 p 或者 q,*      要么 q 是 p 孩子节点,那个节点就是 p(q 和 p 互换),*      要么返回的就是最近公共祖先,*      都可以返回该节点继续回溯,*  3. 如果左右子树均没有返回节点(null),则该子树没有 p 或 q,返回 null*/private TreeNode getAncestor(TreeNode root, TreeNode p, TreeNode q) {if (root == null) {return null;}if (root.val == p.val || root.val == q.val) {return root;}TreeNode left = getAncestor(root.left, p, q);TreeNode right = getAncestor(root.right, p, q);if (left != null && right != null) {return root;} else if (left != null) {return left;} else if (right != null) {return right;} else {return null;}}
}