LeetCode Java刷题笔记—236. 二叉树的最近公共祖先

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

中等难度,和是同一道题,是的升级版。

这种题就是经典的LCA问题,采用递归分治+自底向上后序遍历即可用较少的代码写出来。

public TreeNode lowestCommonAncestor( TreeNode root, TreeNode p, TreeNode 
q ){
          
   
   //递归返回的条件,要么root为null,这表示可能是递归到了最底层
   //要么root等于p或者q,这表示已经找到了等于p或者q的节点,没必要继续向下递归
   if( root == null || root == p || root == q ){
          
   
      return root;
   }
   /*分 拆解*/
   TreeNode left = lowestCommonAncestor( root.left, p, q );
   TreeNode right = lowestCommonAncestor( root.right, p, q );
   /*治 合并*/
   //如果左右子节点都不null,那么表示p和q都是找到了,那么返回root父节点
   //如果有一个子节点为null,那么返回另一个节点,这表示最近公共祖先就是另一个节点

   //最终将会导致这个函数要么返回null,表示没有最近公共祖先
   //要么返回p或者q节点,表示两个节点的最近公共祖先是其中一个节点
   //要么返回root,表示两个节点的最近公共祖先是该节点
   return left == null ? right : right == null ? left : root;
}

另一种方法思想更加简单,我们可以用哈希表存储所有节点的父节点,然后我们就可以利用节点的父节点信息从 p 结点开始不断往上跳,并记录已经访问过的节点,再从 q 节点开始不断往上跳,如果碰到已经访问过的节点,那么这个节点就是我们要找的最近公共祖先。

//存储子节点和父节点的关系映射
Map<Integer, TreeNode> parent = new HashMap<Integer, TreeNode>();

Set<Integer> visited = new HashSet<Integer>();

public TreeNode lowestCommonAncestor( TreeNode root, TreeNode p, TreeNode q ){
          
   
   //将整棵树的父子节点关系存储起来
   dfs( root );
   //循环存储从p节点开始到其父节点的路径
   while( p != null ){
          
   
      visited.add( p.val );
      p = parent.get( p.val );
   }
   //同样从q节点开始循环查找其父节点是否在这条路径中
   while( q != null ){
          
   
      //如果路径中包含q,那么返回q,即q就是最近公共祖先
      if( visited.contains( q.val ) ){
          
   
         return q;
      }
      q = parent.get( q.val );
   }
   return null;
}

/**
 * 将整棵树的父子节点关系存储起来
 *
 * @param root
 */
public void dfs( TreeNode root ){
          
   

   if( root.left != null ){
          
   
      parent.put( root.left.val, root );
      dfs( root.left );
   }
   if( root.right != null ){
          
   
      parent.put( root.right.val, root );
      dfs( root.right );
   }
}
经验分享 程序员 微信小程序 职场和发展