算法习题之树的问题
- 习题1 前缀树
- 习题2 二叉树的先序中序后序遍历
- 习题3 不用递归的形式完成二叉树的先序中序后序遍历
- 习题4 实现二叉树的按层遍历
- 习题5 实现二叉树的序列化和反序列化
- 习题6 把一个N叉数转换成二叉树
- 习题7 如何设计一个打印整棵树的打印函数
- 习题8 求二叉树最宽的层有多少个节点
- 习题9 二叉树结构如下定义:
- 习题10 请把一段纸条竖着放在桌子上,然后从纸条的下边向上方对折1次,压出折痕后展开。此时折痕是凹下去的,即折痕突起的方向指向纸条的背面。 如果从纸条的下边向上方连续对折2次,压出折痕后展开,此时有三条折痕,从上到下依次是下折痕、下折痕和上折痕。 给定一个输入参数N,代表纸条都从下边向上方连续对折N次。 请从上到下打印所有折痕的方向。 例如:N=1时,打印: down N=2时,打印: down down up
- 习题11 判断二叉树是否是完全二叉树
- 习题12 判断二叉树是否是搜索二叉树
- 习题13 给定一棵二叉树的头节点head,返回这颗二叉树是不是平衡二叉树
- 习题14 给定一棵二叉树的头节点head,返回这颗二叉树是不是满二叉树
- 习题15 给定一棵二叉树的头节点head,返回这颗二叉树中最大的二叉搜索子树的大小
- 习题16 给定一棵二叉树的头节点head,任何两个节点之间都存在距离,返回整棵二叉树的最大距离
- 习题17 判断二叉树是否是完全二叉树 如何用递归套路来解这个题
- 习题18 给定一棵二叉树的头节点head,返回这颗二叉树中最大的二叉搜索子树的头节点
- 习题19 给定一棵二叉树的头节点head,和另外两个节点a和b。返回a和b的最低公共祖先
- 习题20 派对的最大快乐值
习题1 前缀树
1)单个字符串中,字符从前到后的加到一棵多叉树上
2)字符放在路上,节点上有专属的数据项(常见的是pass和end值)
3)所有样本都这样添加,如果没有路就新建,如有路就复用
4)沿途节点的pass值增加1,每个字符串结束时来到的节点end值增加1
设计一种结构。用户可以:
1)void insert(String str) 添加某个字符串,可以重复添加,每次算1个
2)int search(String str) 查询某个字符串在结构中还有几个
3) void delete(String str) 删掉某个字符串,可以重复删除,每次算1个
4)int prefixNumber(String str) 查询有多少个字符串,是以str做前缀的
// 固定数组实现
public static class Node1 {
public int pass;
public int end;
public Node1[] nexts;
// char tmp = 'b' (tmp - 'a')
public Node1() {
pass = 0;
end = 0;
// 0 a
// 1 b
// 2 c
// .. ..
// 25 z
// nexts[i] == null i方向的路不存在
// nexts[i] != null i方向的路存在
nexts = new Node1[26];
}
}
public static class Trie1 {
private Node1 root;
public Trie1() {
root = new Node1();
}
public void insert(String word) {
if (word == null) {
return;
}
char[] str = word.toCharArray();
Node1 node = root;
node.pass++;
int path = 0;
for (int i = 0; i < str.length; i++) { // 从左往右遍历字符
path = str[i] - 'a'; // 由字符,对应成走向哪条路
if (node.nexts[path] == null) {
node.nexts[path] = new Node1();
}
node = node.nexts[path];
node.pass++;
}
node.end++;
}
public void delete(String word) {
if (search(word) != 0) {
char[] chs = word.toCharArray();
Node1 node = root;
node.pass--;
int path = 0;
for (int i = 0; i < chs.length; i++) {
path = chs[i] - 'a';
if (--node.nexts[path].pass == 0) {
node.nexts[path] = null;
return;
}
node = node.nexts[path];
}
node.end--;
}
}
// word这个单词之前加入过几次
public int search(String word) {
if (word == null) {
return 0;
}
char[] chs = word.toCharArray();
Node1 node = root;
int index = 0;
for (int i = 0; i < chs.length; i++) {
index = chs[i] - 'a';
if (node.nexts[index] == null) {
return 0;
}
node = node.nexts[index];
}
return node.end;
}
// 所有加入的字符串中,有几个是以pre这个字符串作为前缀的
public int prefixNumber(String pre) {
if (pre == null) {
return 0;
}
char[] chs = pre.toCharArray();
Node1 node = root;
int index = 0;
for (int i = 0; i < chs.length; i++) {
index = chs[i] - 'a';
if (node.nexts[index] == null) {
return 0;
}
node = node.nexts[index];
}
return node.pass;
}
}
// 哈希表的实现
public static class Node2 {
public int pass;
public int end;
public HashMap<Integer, Node2> nexts;
public Node2() {
pass = 0;
end = 0;
nexts = new HashMap<>();
}
}
public static class Trie2 {
private Node2 root;
public Trie2() {
root = new Node2();
}
public void insert(String word) {
if (word == null) {
return;
}
char[] chs = word.toCharArray();
Node2 node = root;
node.pass++;
int index = 0;
for (int i = 0; i < chs.length; i++) {
index = (int) chs[i];
if (!node.nexts.containsKey(index)) {
node.nexts.put(index, new Node2());
}
node = node.nexts.get(index);
node.pass++;
}
node.end++;
}
public void delete(String word) {
if (search(word) != 0) {
char[] chs = word.toCharArray();
Node2 node = root;
node.pass--;
int index = 0;
for (int i = 0; i < chs.length; i++) {
index = (int) chs[i];
if (--node.nexts.get(index).pass == 0) {
node.nexts.remove(index);
return;
}
node = node.nexts.get(index);
}
node.end--;
}
}
// word这个单词之前加入过几次
public int search(String word) {
if (word == null) {
return 0;
}
char[] chs = word.toCharArray();
Node2 node = root;
int index = 0;
for (int i = 0; i < chs.length; i++) {
index = (int) chs[i];
if (!node.nexts.containsKey(index)) {
return 0;
}
node = node.nexts.get(index);
}
return node.end;
}
// 所有加入的字符串中,有几个是以pre这个字符串作为前缀的
public int prefixNumber(String pre) {
if (pre == null) {
return 0;
}
char[] chs = pre.toCharArray();
Node2 node = root;
int index = 0;
for (int i = 0; i < chs.length; i++) {
index = (int) chs[i];
if (!node.nexts.containsKey(index)) {
return 0;
}
node = node.nexts.get(index);
}
return node.pass;
}
}
public static class Right {
private HashMap<String, Integer> box;
public Right() {
box = new HashMap<>();
}
public void insert(String word) {
if (!box.containsKey(word)) {
box.put(word, 1);
} else {
box.put(word, box.get(word) + 1);
}
}
public void delete(String word) {
if (box.containsKey(word)) {
if (box.get(word) == 1) {
box.remove(word);
} else {
box.put(word, box.get(word) - 1);
}
}
}
public int search(String word) {
if (!box.containsKey(word)) {
return 0;
} else {
return box.get(word);
}
}
public int prefixNumber(String pre) {
int count = 0;
for (String cur : box.keySet()) {
if (cur.startsWith(pre)) {
count += box.get(cur);
}
}
return count;
}
}
习题2 二叉树的先序中序后序遍历
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int v) {
value = v;
}
}
public static void f(Node head) {
if (head == null) {
return;
}
// 1
f(head.left);
// 2
f(head.right);
// 3
}
// 先序打印所有节点
public static void pre(Node head) {
if (head == null) {
return;
}
System.out.println(head.value);
pre(head.left);
pre(head.right);
}
public static void in(Node head) {
if (head == null) {
return;
}
in(head.left);
System.out.println(head.value);
in(head.right);
}
public static void pos(Node head) {
if (head == null) {
return;
}
pos(head.left);
pos(head.right);
System.out.println(head.value);
}
public static void main(String[] args) {
Node head = new Node(1);
head.left = new Node(2);
head.right = new Node(3);
head.left.left = new Node(4);
head.left.right = new Node(5);
head.right.left = new Node(6);
head.right.right = new Node(7);
pre(head);
System.out.println("========");
in(head);
System.out.println("========");
pos(head);
System.out.println("========");
}
习题3 不用递归的形式完成二叉树的先序中序后序遍历
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int v) {
value = v;
}
}
public static void pre(Node head) {
System.out.print("pre-order: ");
if (head != null) {
Stack<Node> stack = new Stack<Node>();
stack.add(head);
while (!stack.isEmpty()) {
head = stack.pop();
System.out.print(head.value + " ");
if (head.right != null) {
stack.push(head.right);
}
if (head.left != null) {
stack.push(head.left);
}
}
}
System.out.println();
}
public static void in(Node cur) {
System.out.print("in-order: ");
if (cur != null) {
Stack<Node> stack = new Stack<Node>();
while (!stack.isEmpty() || cur != null) {
if (cur != null) {
stack.push(cur);
cur = cur.left;
} else {
cur = stack.pop();
System.out.print(cur.value + " ");
cur = cur.right;
}
}
}
System.out.println();
}
public static void pos1(Node head) {
System.out.print("pos-order: ");
if (head != null) {
Stack<Node> s1 = new Stack<Node>();
Stack<Node> s2 = new Stack<Node>();
s1.push(head);
while (!s1.isEmpty()) {
head = s1.pop(); // 头 右 左
s2.push(head);
if (head.left != null) {
s1.push(head.left);
}
if (head.right != null) {
s1.push(head.right);
}
}
// 左 右 头
while (!s2.isEmpty()) {
System.out.print(s2.pop().value + " ");
}
}
System.out.println();
}
public static void pos2(Node h) {
System.out.print("pos-order: ");
if (h != null) {
Stack<Node> stack = new Stack<Node>();
stack.push(h);
Node c = null;
while (!stack.isEmpty()) {
c = stack.peek();
if (c.left != null && h != c.left && h != c.right) {
stack.push(c.left);
} else if (c.right != null && h != c.right) {
stack.push(c.right);
} else {
System.out.print(stack.pop().value + " ");
h = c;
}
}
}
System.out.println();
}
public static void main(String[] args) {
Node head = new Node(1);
head.left = new Node(2);
head.right = new Node(3);
head.left.left = new Node(4);
head.left.right = new Node(5);
head.right.left = new Node(6);
head.right.right = new Node(7);
pre(head);
System.out.println("========");
in(head);
System.out.println("========");
pos1(head);
System.out.println("========");
pos2(head);
System.out.println("========");
}
习题4 实现二叉树的按层遍历
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int v) {
value = v;
}
}
public static void level(Node head) {
if (head == null) {
return;
}
Queue<Node> queue = new LinkedList<>();
queue.add(head);
while (!queue.isEmpty()) {
Node cur = queue.poll();
System.out.println(cur.value);
if (cur.left != null) {
queue.add(cur.left);
}
if (cur.right != null) {
queue.add(cur.right);
}
}
}
public static void main(String[] args) {
Node head = new Node(1);
head.left = new Node(2);
head.right = new Node(3);
head.left.left = new Node(4);
head.left.right = new Node(5);
head.right.left = new Node(6);
head.right.right = new Node(7);
level(head);
System.out.println("========");
}
习题5 实现二叉树的序列化和反序列化
/*
* 二叉树可以通过先序、后序或者按层遍历的方式序列化和反序列化,
* 以下代码全部实现了。
* 但是,二叉树无法通过中序遍历的方式实现序列化和反序列化
* 因为不同的两棵树,可能得到同样的中序序列,即便补了空位置也可能一样。
* 比如如下两棵树
* __2
* /
* 1
* 和
* 1__
* \
* 2
* 补足空位置的中序遍历结果都是{ null, 1, null, 2, null}
*
* */
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
public static Queue<String> preSerial(Node head) {
Queue<String> ans = new LinkedList<>();
pres(head, ans);
return ans;
}
public static void pres(Node head, Queue<String> ans) {
if (head == null) {
ans.add(null);
} else {
ans.add(String.valueOf(head.value));
pres(head.left, ans);
pres(head.right, ans);
}
}
public static Queue<String> inSerial(Node head) {
Queue<String> ans = new LinkedList<>();
ins(head, ans);
return ans;
}
public static void ins(Node head, Queue<String> ans) {
if (head == null) {
ans.add(null);
} else {
ins(head.left, ans);
ans.add(String.valueOf(head.value));
ins(head.right, ans);
}
}
public static Queue<String> posSerial(Node head) {
Queue<String> ans = new LinkedList<>();
poss(head, ans);
return ans;
}
public static void poss(Node head, Queue<String> ans) {
if (head == null) {
ans.add(null);
} else {
poss(head.left, ans);
poss(head.right, ans);
ans.add(String.valueOf(head.value));
}
}
public static Node buildByPreQueue(Queue<String> prelist) {
if (prelist == null || prelist.size() == 0) {
return null;
}
return preb(prelist);
}
public static Node preb(Queue<String> prelist) {
String value = prelist.poll();
if (value == null) {
return null;
}
Node head = new Node(Integer.valueOf(value));
head.left = preb(prelist);
head.right = preb(prelist);
return head;
}
public static Node buildByPosQueue(Queue<String> poslist) {
if (poslist == null || poslist.size() == 0) {
return null;
}
// 左右中 -> stack(中右左)
Stack<String> stack = new Stack<>();
while (!poslist.isEmpty()) {
stack.push(poslist.poll());
}
return posb(stack);
}
public static Node posb(Stack<String> posstack) {
String value = posstack.pop();
if (value == null) {
return null;
}
Node head = new Node(Integer.valueOf(value));
head.right = posb(posstack);
head.left = posb(posstack);
return head;
}
public static Queue<String> levelSerial(Node head) {
Queue<String> ans = new LinkedList<>();
if (head == null) {
ans.add(null);
} else {
ans.add(String.valueOf(head.value));
Queue<Node> queue = new LinkedList<Node>();
queue.add(head);
while (!queue.isEmpty()) {
head = queue.poll(); // head 父 子
if (head.left != null) {
ans.add(String.valueOf(head.left.value));
queue.add(head.left);
} else {
ans.add(null);
}
if (head.right != null) {
ans.add(String.valueOf(head.right.value));
queue.add(head.right);
} else {
ans.add(null);
}
}
}
return ans;
}
public static Node buildByLevelQueue(Queue<String> levelList) {
if (levelList == null || levelList.size() == 0) {
return null;
}
Node head = generateNode(levelList.poll());
Queue<Node> queue = new LinkedList<Node>();
if (head != null) {
queue.add(head);
}
Node node = null;
while (!queue.isEmpty()) {
node = queue.poll();
node.left = generateNode(levelList.poll());
node.right = generateNode(levelList.poll());
if (node.left != null) {
queue.add(node.left);
}
if (node.right != null) {
queue.add(node.right);
}
}
return head;
}
public static Node generateNode(String val) {
if (val == null) {
return null;
}
return new Node(Integer.valueOf(val));
}
// for test
public static Node generateRandomBST(int maxLevel, int maxValue) {
return generate(1, maxLevel, maxValue);
}
// for test
public static Node generate(int level, int maxLevel, int maxValue) {
if (level > maxLevel || Math.random() < 0.5) {
return null;
}
Node head = new Node((int) (Math.random() * maxValue));
head.left = generate(level + 1, maxLevel, maxValue);
head.right = generate(level + 1, maxLevel, maxValue);
return head;
}
// for test
public static boolean isSameValueStructure(Node head1, Node head2) {
if (head1 == null && head2 != null) {
return false;
}
if (head1 != null && head2 == null) {
return false;
}
if (head1 == null && head2 == null) {
return true;
}
if (head1.value != head2.value) {
return false;
}
return isSameValueStructure(head1.left, head2.left) && isSameValueStructure(head1.right, head2.right);
}
// for test
public static void printTree(Node head) {
System.out.println("Binary Tree:");
printInOrder(head, 0, "H", 17);
System.out.println();
}
public static void printInOrder(Node head, int height, String to, int len) {
if (head == null) {
return;
}
printInOrder(head.right, height + 1, "v", len);
String val = to + head.value + to;
int lenM = val.length();
int lenL = (len - lenM) / 2;
int lenR = len - lenM - lenL;
val = getSpace(lenL) + val + getSpace(lenR);
System.out.println(getSpace(height * len) + val);
printInOrder(head.left, height + 1, "^", len);
}
public static String getSpace(int num) {
String space = " ";
StringBuffer buf = new StringBuffer("");
for (int i = 0; i < num; i++) {
buf.append(space);
}
return buf.toString();
}
public static void main(String[] args) {
int maxLevel = 5;
int maxValue = 100;
int testTimes = 1000000;
System.out.println("test begin");
for (int i = 0; i < testTimes; i++) {
Node head = generateRandomBST(maxLevel, maxValue);
Queue<String> pre = preSerial(head);
Queue<String> pos = posSerial(head);
Queue<String> level = levelSerial(head);
Node preBuild = buildByPreQueue(pre);
Node posBuild = buildByPosQueue(pos);
Node levelBuild = buildByLevelQueue(level);
if (!isSameValueStructure(preBuild, posBuild) || !isSameValueStructure(posBuild, levelBuild)) {
System.out.println("Oops!");
}
}
System.out.println("test finish!");
}
习题6 把一个N叉数转换成二叉树
public static class Node {
public int val;
public List<Node> children;
public Node() {
}
public Node(int _val) {
val = _val;
}
public Node(int _val, List<Node> _children) {
val = _val;
children = _children;
}
};
// 提交时不要提交这个类
public static class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) {
val = x;
}
}
// 只提交这个类即可
class Codec {
// Encodes an n-ary tree to a binary tree.
public TreeNode encode(Node root) {
if (root == null) {
return null;
}
TreeNode head = new TreeNode(root.val);
head.left = en(root.children);
return head;
}
private TreeNode en(List<Node> children) {
TreeNode head = null;
TreeNode cur = null;
for (Node child : children) {
TreeNode tNode = new TreeNode(child.val);
if (head == null) {
head = tNode;
} else {
cur.right = tNode;
}
cur = tNode;
cur.left = en(child.children);
}
return head;
}
// Decodes your binary tree to an n-ary tree.
public Node decode(TreeNode root) {
if (root == null) {
return null;
}
return new Node(root.val, de(root.left));
}
public List<Node> de(TreeNode root) {
List<Node> children = new ArrayList<>();
while (root != null) {
Node cur = new Node(root.val, de(root.left));
children.add(cur);
root = root.right;
}
return children;
}
}
习题7 如何设计一个打印整棵树的打印函数
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
public static void printTree(Node head) {
System.out.println("Binary Tree:");
printInOrder(head, 0, "H", 17);
System.out.println();
}
public static void printInOrder(Node head, int height, String to, int len) {
if (head == null) {
return;
}
printInOrder(head.right, height + 1, "v", len);
String val = to + head.value + to;
int lenM = val.length();
int lenL = (len - lenM) / 2;
int lenR = len - lenM - lenL;
val = getSpace(lenL) + val + getSpace(lenR);
System.out.println(getSpace(height * len) + val);
printInOrder(head.left, height + 1, "^", len);
}
public static String getSpace(int num) {
String space = " ";
StringBuffer buf = new StringBuffer("");
for (int i = 0; i < num; i++) {
buf.append(space);
}
return buf.toString();
}
public static void main(String[] args) {
Node head = new Node(1);
head.left = new Node(-222222222);
head.right = new Node(3);
head.left.left = new Node(Integer.MIN_VALUE);
head.right.left = new Node(55555555);
head.right.right = new Node(66);
head.left.left.right = new Node(777);
printTree(head);
head = new Node(1);
head.left = new Node(2);
head.right = new Node(3);
head.left.left = new Node(4);
head.right.left = new Node(5);
head.right.right = new Node(6);
head.left.left.right = new Node(7);
printTree(head);
head = new Node(1);
head.left = new Node(1);
head.right = new Node(1);
head.left.left = new Node(1);
head.right.left = new Node(1);
head.right.right = new Node(1);
head.left.left.right = new Node(1);
printTree(head);
}
习题8 求二叉树最宽的层有多少个节点
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
public static int maxWidthUseMap(Node head) {
if (head == null) {
return 0;
}
Queue<Node> queue = new LinkedList<>();
queue.add(head);
// key 在 哪一层,value
HashMap<Node, Integer> levelMap = new HashMap<>();
levelMap.put(head, 1);
int curLevel = 1; // 当前你正在统计哪一层的宽度
int curLevelNodes = 0; // 当前层curLevel层,宽度目前是多少
int max = 0;
while (!queue.isEmpty()) {
Node cur = queue.poll();
int curNodeLevel = levelMap.get(cur);
if (cur.left != null) {
levelMap.put(cur.left, curNodeLevel + 1);
queue.add(cur.left);
}
if (cur.right != null) {
levelMap.put(cur.right, curNodeLevel + 1);
queue.add(cur.right);
}
if (curNodeLevel == curLevel) {
curLevelNodes++;
} else {
max = Math.max(max, curLevelNodes);
curLevel++;
curLevelNodes = 1;
}
}
max = Math.max(max, curLevelNodes);
return max;
}
public static int maxWidthNoMap(Node head) {
if (head == null) {
return 0;
}
Queue<Node> queue = new LinkedList<>();
queue.add(head);
Node curEnd = head; // 当前层,最右节点是谁
Node nextEnd = null; // 下一层,最右节点是谁
int max = 0;
int curLevelNodes = 0; // 当前层的节点数
while (!queue.isEmpty()) {
Node cur = queue.poll();
if (cur.left != null) {
queue.add(cur.left);
nextEnd = cur.left;
}
if (cur.right != null) {
queue.add(cur.right);
nextEnd = cur.right;
}
curLevelNodes++;
if (cur == curEnd) {
max = Math.max(max, curLevelNodes);
curLevelNodes = 0;
curEnd = nextEnd;
}
}
return max;
}
// for test
public static Node generateRandomBST(int maxLevel, int maxValue) {
return generate(1, maxLevel, maxValue);
}
// for test
public static Node generate(int level, int maxLevel, int maxValue) {
if (level > maxLevel || Math.random() < 0.5) {
return null;
}
Node head = new Node((int) (Math.random() * maxValue));
head.left = generate(level + 1, maxLevel, maxValue);
head.right = generate(level + 1, maxLevel, maxValue);
return head;
}
public static void main(String[] args) {
int maxLevel = 10;
int maxValue = 100;
int testTimes = 1000000;
for (int i = 0; i < testTimes; i++) {
Node head = generateRandomBST(maxLevel, maxValue);
if (maxWidthUseMap(head) != maxWidthNoMap(head)) {
System.out.println("Oops!");
}
}
System.out.println("finish!");
}
习题9 二叉树结构如下定义:
Class Node {
V value;
Node left;
Node right;
Node parent;
}
给你二叉树中的某个节点,返回该节点的后继节点
public static class Node {
public int value;
public Node left;
public Node right;
public Node parent;
public Node(int data) {
this.value = data;
}
}
public static Node getSuccessorNode(Node node) {
if (node == null) {
return node;
}
if (node.right != null) {
return getLeftMost(node.right);
} else { // 无右子树
Node parent = node.parent;
while (parent != null && parent.right == node) { // 当前节点是其父亲节点右孩子
node = parent;
parent = node.parent;
}
return parent;
}
}
public static Node getLeftMost(Node node) {
if (node == null) {
return node;
}
while (node.left != null) {
node = node.left;
}
return node;
}
public static void main(String[] args) {
Node head = new Node(6);
head.parent = null;
head.left = new Node(3);
head.left.parent = head;
head.left.left = new Node(1);
head.left.left.parent = head.left;
head.left.left.right = new Node(2);
head.left.left.right.parent = head.left.left;
head.left.right = new Node(4);
head.left.right.parent = head.left;
head.left.right.right = new Node(5);
head.left.right.right.parent = head.left.right;
head.right = new Node(9);
head.right.parent = head;
head.right.left = new Node(8);
head.right.left.parent = head.right;
head.right.left.left = new Node(7);
head.right.left.left.parent = head.right.left;
head.right.right = new Node(10);
head.right.right.parent = head.right;
Node test = head.left.left;
System.out.println(test.value + " next: " + getSuccessorNode(test).value);
test = head.left.left.right;
System.out.println(test.value + " next: " + getSuccessorNode(test).value);
test = head.left;
System.out.println(test.value + " next: " + getSuccessorNode(test).value);
test = head.left.right;
System.out.println(test.value + " next: " + getSuccessorNode(test).value);
test = head.left.right.right;
System.out.println(test.value + " next: " + getSuccessorNode(test).value);
test = head;
System.out.println(test.value + " next: " + getSuccessorNode(test).value);
test = head.right.left.left;
System.out.println(test.value + " next: " + getSuccessorNode(test).value);
test = head.right.left;
System.out.println(test.value + " next: " + getSuccessorNode(test).value);
test = head.right;
System.out.println(test.value + " next: " + getSuccessorNode(test).value);
test = head.right.right; // 10's next is null
System.out.println(test.value + " next: " + getSuccessorNode(test));
}
习题10 请把一段纸条竖着放在桌子上,然后从纸条的下边向上方对折1次,压出折痕后展开。此时折痕是凹下去的,即折痕突起的方向指向纸条的背面。 如果从纸条的下边向上方连续对折2次,压出折痕后展开,此时有三条折痕,从上到下依次是下折痕、下折痕和上折痕。 给定一个输入参数N,代表纸条都从下边向上方连续对折N次。 请从上到下打印所有折痕的方向。 例如:N=1时,打印: down N=2时,打印: down down up
public static void printAllFolds(int N) {
process(1, N, true);
System.out.println();
}
// 当前你来了一个节点,脑海中想象的!
// 这个节点在第i层,一共有N层,N固定不变的
// 这个节点如果是凹的话,down = T
// 这个节点如果是凸的话,down = F
// 函数的功能:中序打印以你想象的节点为头的整棵树!
public static void process(int i, int N, boolean down) {
if (i > N) {
return;
}
process(i + 1, N, true);
System.out.print(down ? "凹 " : "凸 ");
process(i + 1, N, false);
}
public static void main(String[] args) {
int N = 4;
printAllFolds(N);
}
习题11 判断二叉树是否是完全二叉树
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
public static boolean isCBT1(Node head) {
if (head == null) {
return true;
}
LinkedList<Node> queue = new LinkedList<>();
// 是否遇到过左右两个孩子不双全的节点
boolean leaf = false;
Node l = null;
Node r = null;
queue.add(head);
while (!queue.isEmpty()) {
head = queue.poll();
l = head.left;
r = head.right;
if (
// 如果遇到了不双全的节点之后,又发现当前节点不是叶节点
(leaf && (l != null || r != null))
||
(l == null && r != null)
) {
return false;
}
if (l != null) {
queue.add(l);
}
if (r != null) {
queue.add(r);
}
if (l == null || r == null) {
leaf = true;
}
}
return true;
}
public static boolean isCBT2(Node head) {
if (head == null) {
return true;
}
return process(head).isCBT;
}
// 对每一棵子树,是否是满二叉树、是否是完全二叉树、高度
public static class Info {
public boolean isFull;
public boolean isCBT;
public int height;
public Info(boolean full, boolean cbt, int h) {
isFull = full;
isCBT = cbt;
height = h;
}
}
public static Info process(Node X) {
if (X == null) {
return new Info(true, true, 0);
}
Info leftInfo = process(X.left);
Info rightInfo = process(X.right);
int height = Math.max(leftInfo.height, rightInfo.height) + 1;
boolean isFull = leftInfo.isFull
&&
rightInfo.isFull
&& leftInfo.height == rightInfo.height;
boolean isCBT = false;
if (isFull) {
isCBT = true;
} else { // 以x为头整棵树,不满
if (leftInfo.isCBT && rightInfo.isCBT) {
if (leftInfo.isCBT
&& rightInfo.isFull
&& leftInfo.height == rightInfo.height + 1) {
isCBT = true;
}
if (leftInfo.isFull
&&
rightInfo.isFull
&& leftInfo.height == rightInfo.height + 1) {
isCBT = true;
}
if (leftInfo.isFull
&& rightInfo.isCBT && leftInfo.height == rightInfo.height) {
isCBT = true;
}
}
}
return new Info(isFull, isCBT, height);
}
// for test
public static Node generateRandomBST(int maxLevel, int maxValue) {
return generate(1, maxLevel, maxValue);
}
// for test
public static Node generate(int level, int maxLevel, int maxValue) {
if (level > maxLevel || Math.random() < 0.5) {
return null;
}
Node head = new Node((int) (Math.random() * maxValue));
head.left = generate(level + 1, maxLevel, maxValue);
head.right = generate(level + 1, maxLevel, maxValue);
return head;
}
public static void main(String[] args) {
int maxLevel = 5;
int maxValue = 100;
int testTimes = 1000000;
for (int i = 0; i < testTimes; i++) {
Node head = generateRandomBST(maxLevel, maxValue);
if (isCBT1(head) != isCBT2(head)) {
System.out.println("Oops!");
}
}
System.out.println("finish!");
}
习题12 判断二叉树是否是搜索二叉树
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
public static boolean isBST1(Node head) {
if (head == null) {
return true;
}
ArrayList<Node> arr = new ArrayList<>();
in(head, arr);
for (int i = 1; i < arr.size(); i++) {
if (arr.get(i).value <= arr.get(i - 1).value) {
return false;
}
}
return true;
}
public static void in(Node head, ArrayList<Node> arr) {
if (head == null) {
return;
}
in(head.left, arr);
arr.add(head);
in(head.right, arr);
}
public static boolean isBST2(Node head) {
if (head == null) {
return true;
}
return process(head).isBST;
}
public static class Info {
public boolean isBST;
public int max;
public int min;
public Info(boolean i, int ma, int mi) {
isBST = i;
max = ma;
min = mi;
}
}
public static Info process(Node x) {
if (x == null) {
return null;
}
Info leftInfo = process(x.left);
Info rightInfo = process(x.right);
int max = x.value;
if (leftInfo != null) {
max = Math.max(max, leftInfo.max);
}
if (rightInfo != null) {
max = Math.max(max, rightInfo.max);
}
int min = x.value;
if (leftInfo != null) {
min = Math.min(min, leftInfo.min);
}
if (rightInfo != null) {
min = Math.min(min, rightInfo.min);
}
boolean isBST = true;
if (leftInfo != null && !leftInfo.isBST) {
isBST = false;
}
if (rightInfo != null && !rightInfo.isBST) {
isBST = false;
}
if (leftInfo != null && leftInfo.max >= x.value) {
isBST = false;
}
if (rightInfo != null && rightInfo.min <= x.value) {
isBST = false;
}
return new Info(isBST, max, min);
}
// for test
public static Node generateRandomBST(int maxLevel, int maxValue) {
return generate(1, maxLevel, maxValue);
}
// for test
public static Node generate(int level, int maxLevel, int maxValue) {
if (level > maxLevel || Math.random() < 0.5) {
return null;
}
Node head = new Node((int) (Math.random() * maxValue));
head.left = generate(level + 1, maxLevel, maxValue);
head.right = generate(level + 1, maxLevel, maxValue);
return head;
}
public static void main(String[] args) {
int maxLevel = 4;
int maxValue = 100;
int testTimes = 1000000;
for (int i = 0; i < testTimes; i++) {
Node head = generateRandomBST(maxLevel, maxValue);
if (isBST1(head) != isBST2(head)) {
System.out.println("Oops!");
}
}
System.out.println("finish!");
}
习题13 给定一棵二叉树的头节点head,返回这颗二叉树是不是平衡二叉树
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
public static boolean isBalanced1(Node head) {
boolean[] ans = new boolean[1];
ans[0] = true;
process1(head, ans);
return ans[0];
}
public static int process1(Node head, boolean[] ans) {
if (!ans[0] || head == null) {
return -1;
}
int leftHeight = process1(head.left, ans);
int rightHeight = process1(head.right, ans);
if (Math.abs(leftHeight - rightHeight) > 1) {
ans[0] = false;
}
return Math.max(leftHeight, rightHeight) + 1;
}
public static boolean isBalanced2(Node head) {
return process(head).isBalanced;
}
public static class Info{
public boolean isBalanced;
public int height;
public Info(boolean i, int h) {
isBalanced = i;
height = h;
}
}
public static Info process(Node x) {
if(x == null) {
return new Info(true, 0);
}
Info leftInfo = process(x.left);
Info rightInfo = process(x.right);
int height = Math.max(leftInfo.height, rightInfo.height) + 1;
boolean isBalanced = true;
if(!leftInfo.isBalanced) {
isBalanced = false;
}
if(!rightInfo.isBalanced) {
isBalanced = false;
}
if(Math.abs(leftInfo.height - rightInfo.height) > 1) {
isBalanced = false;
}
return new Info(isBalanced, height);
}
// for test
public static Node generateRandomBST(int maxLevel, int maxValue) {
return generate(1, maxLevel, maxValue);
}
// for test
public static Node generate(int level, int maxLevel, int maxValue) {
if (level > maxLevel || Math.random() < 0.5) {
return null;
}
Node head = new Node((int) (Math.random() * maxValue));
head.left = generate(level + 1, maxLevel, maxValue);
head.right = generate(level + 1, maxLevel, maxValue);
return head;
}
public static void main(String[] args) {
int maxLevel = 5;
int maxValue = 100;
int testTimes = 1000000;
for (int i = 0; i < testTimes; i++) {
Node head = generateRandomBST(maxLevel, maxValue);
if (isBalanced1(head) != isBalanced2(head)) {
System.out.println("Oops!");
}
}
System.out.println("finish!");
}
习题14 给定一棵二叉树的头节点head,返回这颗二叉树是不是满二叉树
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
// 第一种方法
// 收集整棵树的高度h,和节点数n
// 只有满二叉树满足 : 2 ^ h - 1 == n
public static boolean isFull1(Node head) {
if (head == null) {
return true;
}
Info1 all = process1(head);
return (1 << all.height) - 1 == all.nodes;
}
public static class Info1 {
public int height;
public int nodes;
public Info1(int h, int n) {
height = h;
nodes = n;
}
}
public static Info1 process1(Node head) {
if (head == null) {
return new Info1(0, 0);
}
Info1 leftInfo = process1(head.left);
Info1 rightInfo = process1(head.right);
int height = Math.max(leftInfo.height, rightInfo.height) + 1;
int nodes = leftInfo.nodes + rightInfo.nodes + 1;
return new Info1(height, nodes);
}
// 第二种方法
// 收集子树是否是满二叉树
// 收集子树的高度
// 左树满 && 右树满 && 左右树高度一样 -> 整棵树是满的
public static boolean isFull2(Node head) {
if (head == null) {
return true;
}
return process2(head).isFull;
}
public static class Info2 {
public boolean isFull;
public int height;
public Info2(boolean f, int h) {
isFull = f;
height = h;
}
}
public static Info2 process2(Node h) {
if (h == null) {
return new Info2(true, 0);
}
Info2 leftInfo = process2(h.left);
Info2 rightInfo = process2(h.right);
boolean isFull = leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height;
int height = Math.max(leftInfo.height, rightInfo.height) + 1;
return new Info2(isFull, height);
}
// for test
public static Node generateRandomBST(int maxLevel, int maxValue) {
return generate(1, maxLevel, maxValue);
}
// for test
public static Node generate(int level, int maxLevel, int maxValue) {
if (level > maxLevel || Math.random() < 0.5) {
return null;
}
Node head = new Node((int) (Math.random() * maxValue));
head.left = generate(level + 1, maxLevel, maxValue);
head.right = generate(level + 1, maxLevel, maxValue);
return head;
}
public static void main(String[] args) {
int maxLevel = 5;
int maxValue = 100;
int testTimes = 1000000;
System.out.println("测试开始");
for (int i = 0; i < testTimes; i++) {
Node head = generateRandomBST(maxLevel, maxValue);
if (isFull1(head) != isFull2(head)) {
System.out.println("出错了!");
}
}
System.out.println("测试结束");
}
习题15 给定一棵二叉树的头节点head,返回这颗二叉树中最大的二叉搜索子树的大小
public static class TreeNode {
public int val;
public TreeNode left;
public TreeNode right;
public TreeNode(int value) {
val = value;
}
}
// 提交如下的代码,可以直接通过
public static int largestBSTSubtree(TreeNode head) {
if (head == null) {
return 0;
}
return process(head).maxBSTSubtreeSize;
}
public static class Info {
public int maxBSTSubtreeSize;
public int allSize;
public int max;
public int min;
public Info(int m, int a, int ma, int mi) {
maxBSTSubtreeSize = m;
allSize = a;
max = ma;
min = mi;
}
}
public static Info process(TreeNode x) {
if (x == null) {
return null;
}
Info leftInfo = process(x.left);
Info rightInfo = process(x.right);
int max = x.val;
int min = x.val;
int allSize = 1;
if (leftInfo != null) {
max = Math.max(leftInfo.max, max);
min = Math.min(leftInfo.min, min);
allSize += leftInfo.allSize;
}
if (rightInfo != null) {
max = Math.max(rightInfo.max, max);
min = Math.min(rightInfo.min, min);
allSize += rightInfo.allSize;
}
int p1 = -1;
if (leftInfo != null) {
p1 = leftInfo.maxBSTSubtreeSize;
}
int p2 = -1;
if (rightInfo != null) {
p2 = rightInfo.maxBSTSubtreeSize;
}
int p3 = -1;
boolean leftBST = leftInfo == null ? true : (leftInfo.maxBSTSubtreeSize == leftInfo.allSize);
boolean rightBST = rightInfo == null ? true : (rightInfo.maxBSTSubtreeSize == rightInfo.allSize);
if (leftBST && rightBST) {
boolean leftMaxLessX = leftInfo == null ? true : (leftInfo.max < x.val);
boolean rightMinMoreX = rightInfo == null ? true : (x.val < rightInfo.min);
if (leftMaxLessX && rightMinMoreX) {
int leftSize = leftInfo == null ? 0 : leftInfo.allSize;
int rightSize = rightInfo == null ? 0 : rightInfo.allSize;
p3 = leftSize + rightSize + 1;
}
}
return new Info(Math.max(p1, Math.max(p2, p3)), allSize, max, min);
}
习题16 给定一棵二叉树的头节点head,任何两个节点之间都存在距离,返回整棵二叉树的最大距离
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
public static int maxDistance1(Node head) {
if (head == null) {
return 0;
}
ArrayList<Node> arr = getPrelist(head);
HashMap<Node, Node> parentMap = getParentMap(head);
int max = 0;
for (int i = 0; i < arr.size(); i++) {
for (int j = i; j < arr.size(); j++) {
max = Math.max(max, distance(parentMap, arr.get(i), arr.get(j)));
}
}
return max;
}
public static ArrayList<Node> getPrelist(Node head) {
ArrayList<Node> arr = new ArrayList<>();
fillPrelist(head, arr);
return arr;
}
public static void fillPrelist(Node head, ArrayList<Node> arr) {
if (head == null) {
return;
}
arr.add(head);
fillPrelist(head.left, arr);
fillPrelist(head.right, arr);
}
public static HashMap<Node, Node> getParentMap(Node head) {
HashMap<Node, Node> map = new HashMap<>();
map.put(head, null);
fillParentMap(head, map);
return map;
}
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 int distance(HashMap<Node, Node> parentMap, Node o1, Node o2) {
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);
}
Node lowestAncestor = cur;
cur = o1;
int distance1 = 1;
while (cur != lowestAncestor) {
cur = parentMap.get(cur);
distance1++;
}
cur = o2;
int distance2 = 1;
while (cur != lowestAncestor) {
cur = parentMap.get(cur);
distance2++;
}
return distance1 + distance2 - 1;
}
public static int maxDistance2(Node head) {
return process(head).maxDistance;
}
public static class Info {
public int maxDistance;
public int height;
public Info(int m, int h) {
maxDistance = m;
height = h;
}
}
public static Info process(Node x) {
if (x == null) {
return new Info(0, 0);
}
Info leftInfo = process(x.left);
Info rightInfo = process(x.right);
int height = Math.max(leftInfo.height, rightInfo.height) + 1;
int p1 = leftInfo.maxDistance;
int p2 = rightInfo.maxDistance;
int p3 = leftInfo.height + rightInfo.height + 1;
int maxDistance = Math.max(Math.max(p1, p2), p3);
return new Info(maxDistance, height);
}
// for test
public static Node generateRandomBST(int maxLevel, int maxValue) {
return generate(1, maxLevel, maxValue);
}
// for test
public static Node generate(int level, int maxLevel, int maxValue) {
if (level > maxLevel || Math.random() < 0.5) {
return null;
}
Node head = new Node((int) (Math.random() * maxValue));
head.left = generate(level + 1, maxLevel, maxValue);
head.right = generate(level + 1, maxLevel, maxValue);
return head;
}
public static void main(String[] args) {
int maxLevel = 4;
int maxValue = 100;
int testTimes = 1000000;
for (int i = 0; i < testTimes; i++) {
Node head = generateRandomBST(maxLevel, maxValue);
if (maxDistance1(head) != maxDistance2(head)) {
System.out.println("Oops!");
}
}
System.out.println("finish!");
}
习题17 判断二叉树是否是完全二叉树 如何用递归套路来解这个题
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
public static boolean isCBT1(Node head) {
if (head == null) {
return true;
}
LinkedList<Node> queue = new LinkedList<>();
// 是否遇到过左右两个孩子不双全的节点
boolean leaf = false;
Node l = null;
Node r = null;
queue.add(head);
while (!queue.isEmpty()) {
head = queue.poll();
l = head.left;
r = head.right;
if (
// 如果遇到了不双全的节点之后,又发现当前节点不是叶节点
(leaf && (l != null || r != null)) || (l == null && r != null)
) {
return false;
}
if (l != null) {
queue.add(l);
}
if (r != null) {
queue.add(r);
}
if (l == null || r == null) {
leaf = true;
}
}
return true;
}
public static boolean isCBT2(Node head) {
return process(head).isCBT;
}
public static class Info {
public boolean isFull;
public boolean isCBT;
public int height;
public Info(boolean full, boolean cbt, int h) {
isFull = full;
isCBT = cbt;
height = h;
}
}
public static Info process(Node x) {
if (x == null) {
return new Info(true, true, 0);
}
Info leftInfo = process(x.left);
Info rightInfo = process(x.right);
int height = Math.max(leftInfo.height, rightInfo.height) + 1;
boolean isFull = leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height;
boolean isCBT = false;
if (leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height) {
isCBT = true;
} else if (leftInfo.isCBT && rightInfo.isFull && leftInfo.height == rightInfo.height + 1) {
isCBT = true;
} else if (leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height + 1) {
isCBT = true;
} else if (leftInfo.isFull && rightInfo.isCBT && leftInfo.height == rightInfo.height) {
isCBT = true;
}
return new Info(isFull, isCBT, height);
}
// for test
public static Node generateRandomBST(int maxLevel, int maxValue) {
return generate(1, maxLevel, maxValue);
}
// for test
public static Node generate(int level, int maxLevel, int maxValue) {
if (level > maxLevel || Math.random() < 0.5) {
return null;
}
Node head = new Node((int) (Math.random() * maxValue));
head.left = generate(level + 1, maxLevel, maxValue);
head.right = generate(level + 1, maxLevel, maxValue);
return head;
}
public static void main(String[] args) {
int maxLevel = 5;
int maxValue = 100;
int testTimes = 1000000;
for (int i = 0; i < testTimes; i++) {
Node head = generateRandomBST(maxLevel, maxValue);
if (isCBT1(head) != isCBT2(head)) {
System.out.println("Oops!");
}
}
System.out.println("finish!");
}
习题18 给定一棵二叉树的头节点head,返回这颗二叉树中最大的二叉搜索子树的头节点
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
public static int getBSTSize(Node head) {
if (head == null) {
return 0;
}
ArrayList<Node> arr = new ArrayList<>();
in(head, arr);
for (int i = 1; i < arr.size(); i++) {
if (arr.get(i).value <= arr.get(i - 1).value) {
return 0;
}
}
return arr.size();
}
public static void in(Node head, ArrayList<Node> arr) {
if (head == null) {
return;
}
in(head.left, arr);
arr.add(head);
in(head.right, arr);
}
public static Node maxSubBSTHead1(Node head) {
if (head == null) {
return null;
}
if (getBSTSize(head) != 0) {
return head;
}
Node leftAns = maxSubBSTHead1(head.left);
Node rightAns = maxSubBSTHead1(head.right);
return getBSTSize(leftAns) >= getBSTSize(rightAns) ? leftAns : rightAns;
}
public static Node maxSubBSTHead2(Node head) {
if (head == null) {
return null;
}
return process(head).maxSubBSTHead;
}
// 每一棵子树
public static class Info {
public Node maxSubBSTHead;
public int maxSubBSTSize;
public int min;
public int max;
public Info(Node h, int size, int mi, int ma) {
maxSubBSTHead = h;
maxSubBSTSize = size;
min = mi;
max = ma;
}
}
public static Info process(Node X) {
if (X == null) {
return null;
}
Info leftInfo = process(X.left);
Info rightInfo = process(X.right);
int min = X.value;
int max = X.value;
Node maxSubBSTHead = null;
int maxSubBSTSize = 0;
if (leftInfo != null) {
min = Math.min(min, leftInfo.min);
max = Math.max(max, leftInfo.max);
maxSubBSTHead = leftInfo.maxSubBSTHead;
maxSubBSTSize = leftInfo.maxSubBSTSize;
}
if (rightInfo != null) {
min = Math.min(min, rightInfo.min);
max = Math.max(max, rightInfo.max);
if (rightInfo.maxSubBSTSize > maxSubBSTSize) {
maxSubBSTHead = rightInfo.maxSubBSTHead;
maxSubBSTSize = rightInfo.maxSubBSTSize;
}
}
if ((leftInfo == null ? true : (leftInfo.maxSubBSTHead == X.left && leftInfo.max < X.value))
&& (rightInfo == null ? true : (rightInfo.maxSubBSTHead == X.right && rightInfo.min > X.value))) {
maxSubBSTHead = X;
maxSubBSTSize = (leftInfo == null ? 0 : leftInfo.maxSubBSTSize)
+ (rightInfo == null ? 0 : rightInfo.maxSubBSTSize) + 1;
}
return new Info(maxSubBSTHead, maxSubBSTSize, min, max);
}
// for test
public static Node generateRandomBST(int maxLevel, int maxValue) {
return generate(1, maxLevel, maxValue);
}
// for test
public static Node generate(int level, int maxLevel, int maxValue) {
if (level > maxLevel || Math.random() < 0.5) {
return null;
}
Node head = new Node((int) (Math.random() * maxValue));
head.left = generate(level + 1, maxLevel, maxValue);
head.right = generate(level + 1, maxLevel, maxValue);
return head;
}
public static void main(String[] args) {
int maxLevel = 4;
int maxValue = 100;
int testTimes = 1000000;
for (int i = 0; i < testTimes; i++) {
Node head = generateRandomBST(maxLevel, maxValue);
if (maxSubBSTHead1(head) != maxSubBSTHead2(head)) {
System.out.println("Oops!");
}
}
System.out.println("finish!");
}
习题19 给定一棵二叉树的头节点head,和另外两个节点a和b。返回a和b的最低公共祖先
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
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 lowestAncestor2(Node head, Node a, Node b) {
return process(head, a, b).ans;
}
public static class Info {
public boolean findA;
public boolean findB;
public Node ans;
public Info(boolean fA, boolean fB, Node an) {
findA = fA;
findB = fB;
ans = an;
}
}
public static Info process(Node x, Node a, Node b) {
if (x == null) {
return new Info(false, false, null);
}
Info leftInfo = process(x.left, a, b);
Info rightInfo = process(x.right, a, b);
boolean findA = (x == a) || leftInfo.findA || rightInfo.findA;
boolean findB = (x == b) || leftInfo.findB || rightInfo.findB;
Node ans = null;
if (leftInfo.ans != null) {
ans = leftInfo.ans;
} else if (rightInfo.ans != null) {
ans = rightInfo.ans;
} else {
if (findA && findB) {
ans = x;
}
}
return new Info(findA, findB, ans);
}
// for test
public static Node generateRandomBST(int maxLevel, int maxValue) {
return generate(1, maxLevel, maxValue);
}
// for test
public static Node generate(int level, int maxLevel, int maxValue) {
if (level > maxLevel || Math.random() < 0.5) {
return null;
}
Node head = new Node((int) (Math.random() * maxValue));
head.left = generate(level + 1, maxLevel, maxValue);
head.right = generate(level + 1, maxLevel, maxValue);
return head;
}
// for test
public static Node pickRandomOne(Node head) {
if (head == null) {
return null;
}
ArrayList<Node> arr = new ArrayList<>();
fillPrelist(head, arr);
int randomIndex = (int) (Math.random() * arr.size());
return arr.get(randomIndex);
}
// for test
public static void fillPrelist(Node head, ArrayList<Node> arr) {
if (head == null) {
return;
}
arr.add(head);
fillPrelist(head.left, arr);
fillPrelist(head.right, arr);
}
public static void main(String[] args) {
int maxLevel = 4;
int maxValue = 100;
int testTimes = 1000000;
for (int i = 0; i < testTimes; i++) {
Node head = generateRandomBST(maxLevel, maxValue);
Node o1 = pickRandomOne(head);
Node o2 = pickRandomOne(head);
if (lowestAncestor1(head, o1, o2) != lowestAncestor2(head, o1, o2)) {
System.out.println("Oops!");
}
}
System.out.println("finish!");
}
习题20 派对的最大快乐值
员工信息的定义如下:
class Employee {
public int happy; // 这名员工可以带来的快乐值
List subordinates; // 这名员工有哪些直接下级
}
公司的每个员工都符合 Employee 类的描述。整个公司的人员结构可以看作是一棵标准的、 没有环的多叉树。树的头节点是公司唯一的老板。除老板之外的每个员工都有唯一的直接上级。 叶节点是没有任何下属的基层员工(subordinates列表为空),除基层员工外,每个员工都有一个或多个直接下级。
这个公司现在要办party,你可以决定哪些员工来,哪些员工不来,规则:
1.如果某个员工来了,那么这个员工的所有直接下级都不能来
2.派对的整体快乐值是所有到场员工快乐值的累加
3.你的目标是让派对的整体快乐值尽量大
给定一棵多叉树的头节点boss,请返回派对的最大快乐值。
public static class Employee {
public int happy;
public List<Employee> nexts;
public Employee(int h) {
happy = h;
nexts = new ArrayList<>();
}
}
public static int maxHappy1(Employee boss) {
if (boss == null) {
return 0;
}
return process1(boss, false);
}
// 当前来到的节点叫cur,
// up表示cur的上级是否来,
// 该函数含义:
// 如果up为true,表示在cur上级已经确定来,的情况下,cur整棵树能够提供最大的快乐值是多少?
// 如果up为false,表示在cur上级已经确定不来,的情况下,cur整棵树能够提供最大的快乐值是多少?
public static int process1(Employee cur, boolean up) {
if (up) { // 如果cur的上级来的话,cur没得选,只能不来
int ans = 0;
for (Employee next : cur.nexts) {
ans += process1(next, false);
}
return ans;
} else { // 如果cur的上级不来的话,cur可以选,可以来也可以不来
int p1 = cur.happy;
int p2 = 0;
for (Employee next : cur.nexts) {
p1 += process1(next, true);
p2 += process1(next, false);
}
return Math.max(p1, p2);
}
}
public static int maxHappy2(Employee head) {
Info allInfo = process(head);
return Math.max(allInfo.no, allInfo.yes);
}
public static class Info {
public int no;
public int yes;
public Info(int n, int y) {
no = n;
yes = y;
}
}
public static Info process(Employee x) {
if (x == null) {
return new Info(0, 0);
}
int no = 0;
int yes = x.happy;
for (Employee next : x.nexts) {
Info nextInfo = process(next);
no += Math.max(nextInfo.no, nextInfo.yes);
yes += nextInfo.no;
}
return new Info(no, yes);
}
// for test
public static Employee genarateBoss(int maxLevel, int maxNexts, int maxHappy) {
if (Math.random() < 0.02) {
return null;
}
Employee boss = new Employee((int) (Math.random() * (maxHappy + 1)));
genarateNexts(boss, 1, maxLevel, maxNexts, maxHappy);
return boss;
}
// for test
public static void genarateNexts(Employee e, int level, int maxLevel, int maxNexts, int maxHappy) {
if (level > maxLevel) {
return;
}
int nextsSize = (int) (Math.random() * (maxNexts + 1));
for (int i = 0; i < nextsSize; i++) {
Employee next = new Employee((int) (Math.random() * (maxHappy + 1)));
e.nexts.add(next);
genarateNexts(next, level + 1, maxLevel, maxNexts, maxHappy);
}
}
public static void main(String[] args) {
int maxLevel = 4;
int maxNexts = 7;
int maxHappy = 100;
int testTimes = 100000;
for (int i = 0; i < testTimes; i++) {
Employee boss = genarateBoss(maxLevel, maxNexts, maxHappy);
if (maxHappy1(boss) != maxHappy2(boss)) {
System.out.println("Oops!");
}
}
System.out.println("finish!");
}