题目:
给定一个二叉树的头结点head,和另外两个节点a和b,返回a和b的最低公共祖先。
递归方式:
- 递归收集左右子树信息,并进行汇总。
- 在左右树中找a、b节点并进行标记。
- a、b在左树汇聚,公共祖先在左树
- a、b在右树汇聚,公共祖先在右树
- 当前节点Node就是祖先本身。
- 左右树都没有,则头结点就是最低公共祖先。
- 所以需要3个变量boolean findA,boolean findB,和最终找到的公共祖先Node 。
递归方式
//根据需要收集的信息创建Info类
public static class Info {
//是否找到A节点
public boolean findA;
//是否找到B节点
public boolean findB;
//公共祖先节点
public Node ans;
public Info(boolean fA, boolean fB, Node an) {
findA = fA;
findB = fB;
ans = an;
}
}
// 1
// 3 7
// 4 9
//2 6
public static Node lowestAncestor(Node head,Node a,Node b){
if (head == null){
return head;
}
return process(head,a,b).ans;
}
public static Info process(Node head,Node a,Node b){
if (head == null){
//构建Info信息,如果为null,则代表没找到a、b节点信息,并且ans为null
return new Info(false,false,null);
}
//左右子节点递归收集信息
Info leftInfo = process(head.left,a,b);
Info rightInfo = process(head.right,a,b);
//构建当前节点信息 如果在左右子树中,找到过a、b节点,则标记为true,当前节点等于a、b 也标记为true
boolean findA = head == a || leftInfo.findA || rightInfo.findA;
boolean findB = head == b || leftInfo.findB || rightInfo.findB;
Node ans = null;
//如果左子树中找到了最低公共祖先,ans = leftInfo.ans
if (leftInfo.ans != null){
ans = leftInfo.ans;
}else if(rightInfo.ans != null){
ans = rightInfo.ans;
}else{
//如果此时已经找到了a和b,则代表当前节点就是ans。
if (findA && findB){
ans = head;
}
}
return new Info(findA,findB,ans);
}
暴力方式
- 遍历整棵树并放到Map中,key:每个节点 value:对应节点的父节点
- 准备一个set集合,遍历map,将a以及a的所有父节点都放入到set中
- 看set中是否包含b节点,如果不包含,则循环获取b的父节点,直到b的父节点在set集合中存在
- 返回当前节点,就是a、b的公共祖先
public static Node lowestAncestor1(Node head, Node o1, Node o2) {
if (head == null) {
return null;
}
// key的父节点是value
HashMap<Node, Node> parentMap = new HashMap<>();
parentMap.put(head, null);
fillParentMap(head, parentMap);
HashSet<Node> o1Set = new HashSet<>();
Node cur = o1;
o1Set.add(cur);
while (parentMap.get(cur) != null) {
cur = parentMap.get(cur);
o1Set.add(cur);
}
cur = o2;
while (!o1Set.contains(cur)) {
cur = parentMap.get(cur);
}
return cur;
}
public static void fillParentMap(Node head, HashMap<Node, Node> parentMap) {
if (head.left != null) {
parentMap.put(head.left, head);
fillParentMap(head.left, parentMap);
}
if (head.right != null) {
parentMap.put(head.right, head);
fillParentMap(head.right, parentMap);
}
}
对数器
public static Node generateRandomBST(int maxLength, int maxValue) {
return generateNode(1, maxLength, maxValue);
}
public static Node generateNode(int level, int maxLength, int maxValue) {
if (level > maxLength || Math.random() < 0.5) {
return null;
}
Node head = new Node((int) (Math.random() * maxValue));
head.left = generateNode(level + 1, maxLength, maxValue);
head.right = generateNode(level + 1, maxLength, maxValue);
return head;
}
public static Node pickRandomOne(Node head) {
if (head == null) {
return null;
}
List<Node> list = new ArrayList<>();
fillList(head, list);
int randomSize = (int) (Math.random() * list.size());
return list.get(randomSize);
}
private static void fillList(Node head, List<Node> list) {
if (head == null) {
return;
}
list.add(head);
fillList(head.left, list);
fillList(head.right, list);
}
public static void main(String[] args) {
int maxValue = 10;
int maxLength = 5;
int testNum = 1000;
for (int i = 0; i<testNum;i++){
//随机一棵树
Node head = generateRandomBST(maxLength,maxValue);
//在树中随机获取a、b节点
Node a = pickRandomOne(head);
Node b = pickRandomOne(head);
Node ans1 = lowestAncestor1(head, a, b);
Node ans2 = lowestAncestor2(head,a,b);
if (ans1 != ans2){
System.out.println("Fucking Fuck!!!!!");
break;
}
}
System.out.println("finish");
}