​welcome to my blog​

LeetCode Top 100 Liked Questions 236. Lowest Common Ancestor of a Binary Tree (Java版; Medium)

题目描述

Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree.

According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).”

Given the following binary tree: root = [3,5,1,6,2,0,8,null,null,7,4]

LeetCode Top 100 Liked Questions 236. Lowest Common Ancestor of a Binary Tree (Java版; Medium)_LeetCode

Example 1:

Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
Output: 3
Explanation: The LCA of nodes 5 and 1 is 3.
Example 2:

Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
Output: 5
Explanation: The LCA of nodes 5 and 4 is 5, since a node can be a descendant of itself according to the LCA definition.

Note:

All of the nodes' values will be unique.
p and q are different and both values will exist in the binary tree.

第一次做; 最优解; 核心:递归函数的返回值. 递归函数有时候返回的是p或者q; 有时候返回的是p和q的最低公共祖先, 如果最终接收到的返回值是p或者q, 说明这两个节点:一个是另一个祖先

class Solution {
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);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if(left!=null && right!=null)
return root;
return left!=null ? left : right;
}
}

第一次做;遍历二叉树, 使用哈希表记录每个节点的父节点; 将p到root途径的每个节点添加到path中, 然后从q开始往root走, 如果沿途经过的某个节点出现在path中, 那么这个节点就是p和q的最低公共祖先; 记录父节点方式2: 把当前节点作为孩子节点, 递归函数中需要增加一个父节点参数, 用来记录当前节点的父节点

import java.util.HashMap;
import java.util.HashSet;

class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null)
return root;
HashMap<TreeNode, TreeNode> fatherOf = new HashMap<>();
//建表, 记录每个节点的父节点
establish(null, root, fatherOf);
//记录p到root的路径
HashSet<TreeNode> path = new HashSet<>();
TreeNode curr = p;
while(curr!=null){
path.add(curr);
curr = fatherOf.get(curr);
}
//遍历q到root的路径, 如果沿途某个节点在path中出现过, 这个节点就是p和q的最低公共祖先
curr = q;
while(curr!=null){
if(path.contains(curr))
return curr;
curr = fatherOf.get(curr);
}
//跳出循环说明p和q没有公共祖先, 其实是说明树上不同时存在p和q, 不过题目确保了树上存在p和q, 所以不会执行到这里
return null;


}
public void establish(TreeNode father, TreeNode head, HashMap<TreeNode, TreeNode> fatherOf){
if(head==null)
return;
//execute
fatherOf.put(head, father);
establish(head, head.left, fatherOf);
establish(head, head.right, fatherOf);
}
}

第一次做;遍历二叉树, 使用哈希表记录每个节点的父节点; 根节点父节点设为null; 将p到root经过的节点添加到path中, 然后从q开始往root走, 如果沿途经过的某个节点出现在path中, 那么这个节点就是p和q的最低公共祖先; 记录父节点方式1: 把当前节点作为父节点

建表时最直接的想法是在函数传递过程中记录当前节点的父节点
另一种想法是, 把当前节点当做父节点, 更新当前节点子节点的fatherOf, 这种方法不需要在函数中单独传递父节点
把两种建表的方式都实现一下
import java.util.HashMap;
import java.util.HashSet;

class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null)
return root;
HashMap<TreeNode, TreeNode> fatherOf = new HashMap<>();
//建表, 记录每个节点的父节点
establish(root, fatherOf);
//记录p到root的路径
HashSet<TreeNode> path = new HashSet<>();
TreeNode curr = p;
while(curr!=null){
path.add(curr);
curr = fatherOf.get(curr);
}
//遍历q到root的路径, 如果沿途某个节点在path中出现过, 这个节点就是p和q的最低公共祖先
curr = q;
while(curr!=null){
if(path.contains(curr))
return curr;
curr = fatherOf.get(curr);
}
//跳出循环说明p和q没有公共祖先, 其实是说明树上不同时存在p和q, 不过题目确保了树上存在p和q, 所以不会执行到这里
return null;


}
public void establish(TreeNode head, HashMap<TreeNode, TreeNode> fatherOf){
if(head==null)
return;
/*
这一句是建表过程中最关键的一句话, 将会影响到如何建表
建表时最直接的想法是在函数传递过程中记录当前节点的父节点
另一种想法是, 把当前节点当做父节点, 更新当前节点子节点的fatherOf, 这种方法不需要在函数中单独传递父节点
把两种建表的方式都实现一下
*/
if(fatherOf.isEmpty())
//fatherOf为空, 说明当前节点是根节点, 根节点的父节点设为null
fatherOf.put(head, null);
//execute
if(head.left!=null){
fatherOf.put(head.left, head);
establish(head.left, fatherOf);
}

if(head.right!=null){
fatherOf.put(head.right, head);
establish(head.right, fatherOf);
}
}
}