package class02;
import org.junit.Test;
import java.util.*;
public class Study230604 {
//继续二叉树的练习,定义节点
public class Node {
String val;
Node left;
Node right;
Node parent;//辅助父节点
public Node(String val) {
this.val = val;
}
}
//问题1:给定一棵二叉树head上的两个节点Node1和Node2,求Node1和Node2的最低公共祖先
//方案一:分别找到Node1节点和Node2的族谱比对即可!,利用后序遍历
public Node question1(Node head, Node n1, Node n2) {
Queue<Node> queue = new LinkedList<>(); //队列中存放遍历序列
question1_1(head, queue); //递归实现后序列
System.out.println(" ");
question1_2(head, queue); //非递归实现后序
//建立两个遍历指针,在出队列的时候记录族谱
Node cur1 = n1;
Node cur2 = n2;
while (!queue.isEmpty()) {
Node cur = queue.poll();
if (cur.left == cur1 || cur.right == cur1) {
cur1.parent = cur;
cur1 = cur;
}
if (cur.left == cur2 || cur.right == cur2) {
cur2.parent = cur;
cur2 = cur;
}
} //n1和n2分别是对应的族谱头,向上遍历的
//接下来就是判断n1和n2的第一个相同节点,采用先将n1放入hashset中,
//再遍历一次n2,如果存在则结束,返回存在的哪个节点就是答案
cur1 = n1;
cur2 = n2;
HashSet<Node> nodes = new HashSet<>();
while (cur1 != null) {
nodes.add(cur1);
cur1 = cur1.parent;
}
while (cur2 != null) {
if (nodes.contains(cur2)) {
return cur2;
}
cur2 = cur2.parent;
}
return null;
}
//递归实现后序遍历存放数据,队列中 存放遍历序列
public void question1_1(Node head, Queue<Node> queue) {
if (head != null) {
question1_1(head.left, queue);
question1_1(head.right, queue);
System.out.print(head.val + " ");
queue.add(head);
}
}
//练习:非递归实现后序遍历存放数据,队列中 存放遍历序列
public void question1_2(Node head, Queue<Node> queue) {
Node cur;
Node temp = null; //记录之前打印的节点
Stack<Node> stack = new Stack<>();
stack.push(head);
while (!stack.empty()) {
cur = stack.peek();
if (cur.left != null && temp != cur.left && temp != cur.right) {
stack.push(cur.left);
} else if (cur.right != null && temp != cur.right) {
stack.push(cur.right);
} else { //左右均为空,考虑出栈并打印(在这里就是入队列)
Node pop = stack.pop();
System.out.print(pop.val + " ");
queue.add(pop);
temp = cur;
}
}
}
//问题2:给定一棵二叉树head上的两个节点Node1和Node2,求Node1和Node2的最低公共祖先
//优化方案:存在两种可能性
//1==>n1/n2互为祖先 ==>返回n1/或者n2
//2==>n1/n2有共同的祖先==>返回祖先Node
//我们采用追溯法:假设对应一个节点X我们可以给他的父亲节点返回信息
//如果X是n1或者n2,那我们就返回X给他的父亲P,不是就返回null,同样的,父亲在接受在接受孩子的信息时候
//信息全是空,则向上返回空,否则就是返回非空的那个信息
public Node question2(Node head, Node n1, Node n2) {
if (head == null || head == n1 || head == n2) { //注意返回条件,这个也是情况1下的条件
return head;
}
Node left = question2(head.left, n1, n2);
Node right = question2(head.right, n1, n2);
if (left != null && right != null) {
return head;
} else if (left != null) {
return left;
} else return right;
}
@Test
public void Test() {
Node a = new Node("A");
Node b = new Node("B");
Node c = new Node("C");
Node d = new Node("D");
Node e = new Node("E");
Node f = new Node("F");
Node g = new Node("G");
a.left = b;
a.right = c;
b.left = d;
b.right = e;
e.left = f;
d.right = g;
System.out.println("最低祖先:" + question2(a, c, e).val);
}
}
package class02;
import org.junit.Test;
import java.util.*;
public class Study230604 {
//继续二叉树的练习,定义节点
public class Node {
String val;
Node left;
Node right;
Node parent;//辅助父节点
public Node(String val) {
this.val = val;
}
}
//问题1:给定一棵二叉树head上的两个节点Node1和Node2,求Node1和Node2的最低公共祖先
//方案一:分别找到Node1节点和Node2的族谱比对即可!,利用后序遍历
public Node question1(Node head, Node n1, Node n2) {
Queue<Node> queue = new LinkedList<>(); //队列中存放遍历序列
question1_1(head, queue); //递归实现后序列
System.out.println(" ");
question1_2(head, queue); //非递归实现后序
//建立两个遍历指针,在出队列的时候记录族谱
Node cur1 = n1;
Node cur2 = n2;
while (!queue.isEmpty()) {
Node cur = queue.poll();
if (cur.left == cur1 || cur.right == cur1) {
cur1.parent = cur;
cur1 = cur;
}
if (cur.left == cur2 || cur.right == cur2) {
cur2.parent = cur;
cur2 = cur;
}
} //n1和n2分别是对应的族谱头,向上遍历的
//接下来就是判断n1和n2的第一个相同节点,采用先将n1放入hashset中,
//再遍历一次n2,如果存在则结束,返回存在的哪个节点就是答案
cur1 = n1;
cur2 = n2;
HashSet<Node> nodes = new HashSet<>();
while (cur1 != null) {
nodes.add(cur1);
cur1 = cur1.parent;
}
while (cur2 != null) {
if (nodes.contains(cur2)) {
return cur2;
}
cur2 = cur2.parent;
}
return null;
}
//递归实现后序遍历存放数据,队列中 存放遍历序列
public void question1_1(Node head, Queue<Node> queue) {
if (head != null) {
question1_1(head.left, queue);
question1_1(head.right, queue);
System.out.print(head.val + " ");
queue.add(head);
}
}
//练习:非递归实现后序遍历存放数据,队列中 存放遍历序列
public void question1_2(Node head, Queue<Node> queue) {
Node cur;
Node temp = null; //记录之前打印的节点
Stack<Node> stack = new Stack<>();
stack.push(head);
while (!stack.empty()) {
cur = stack.peek();
if (cur.left != null && temp != cur.left && temp != cur.right) {
stack.push(cur.left);
} else if (cur.right != null && temp != cur.right) {
stack.push(cur.right);
} else { //左右均为空,考虑出栈并打印(在这里就是入队列)
Node pop = stack.pop();
System.out.print(pop.val + " ");
queue.add(pop);
temp = cur;
}
}
}
//问题2:给定一棵二叉树head上的两个节点Node1和Node2,求Node1和Node2的最低公共祖先
//优化方案:存在两种可能性
//1==>n1/n2互为祖先 ==>返回n1/或者n2
//2==>n1/n2有共同的祖先==>返回祖先Node
//我们采用追溯法:假设对应一个节点X我们可以给他的父亲节点返回信息
//如果X是n1或者n2,那我们就返回X给他的父亲P,不是就返回null,同样的,父亲在接受在接受孩子的信息时候
//信息全是空,则向上返回空,否则就是返回非空的那个信息
public Node question2(Node head, Node n1, Node n2) {
if (head == null || head == n1 || head == n2) { //注意返回条件,这个也是情况1下的条件
return head;
}
Node left = question2(head.left, n1, n2);
Node right = question2(head.right, n1, n2);
if (left != null && right != null) {
return head;
} else if (left != null) {
return left;
} else return right;
}
@Test
public void Test() {
Node a = new Node("A");
Node b = new Node("B");
Node c = new Node("C");
Node d = new Node("D");
Node e = new Node("E");
Node f = new Node("F");
Node g = new Node("G");
a.left = b;
a.right = c;
b.left = d;
b.right = e;
e.left = f;
d.right = g;
System.out.println("最低祖先:" + question2(a, c, e).val);
}
}