public static Node getTreeFromArr2(int[] arr) {
if (arr == null || arr.length == 0) {
return null;
}
LinkedList quque = new LinkedList<>();
Node root = new Node(arr[0]);
quque.add(root);
int index = 1;
while(!quque.isEmpty()){
// pop 0的时候,刚好操作1、2
// pop 1的时候,刚好操作3、4
// pop 2的时候,刚好操作5、6
Node temp = quque.pop();
if(index < arr.length){
temp.left = new Node(arr[index]);
quque.add(temp.left);
index++;
}
if(index < arr.length){
temp.right = new Node(arr[index]);
quque.add(temp.right);
index++;
}
}
return root;
}
private static Node getTreeFromArr(int[] arr) {
Map map = new HashMap();
for (int i = arr.length - 1; i >= 0; i--) {
Node temp = new Node(arr[i]);
temp.value = arr[i];
map.put(i, temp);
int leftChildIndex = 2 * i + 1;
int rightChildIndex = 2 * i + 2;
if (leftChildIndex < arr.length) {
temp.left = map.get(leftChildIndex);
}
if (rightChildIndex < arr.length) {
temp.right = map.get(rightChildIndex);
}
}
return map.get(0);
}
@ToString
public static class Node {
public Node left;
public Node right;
public int value;
public Node(int value) {
this.value = value;
}
}
public static void main(String[] args) {
int[] arr = {0, 1, 2, 3, 4, 5, 6};
// Node head = getTreeFromArr(arr);
Node head2 = getTreeFromArr2(arr);
// System.out.println(JSON.toJSONString(head));
System.out.println(JSON.toJSONString(head2));
/*
前序遍历:[0, 1, 3, 4, 2, 5, 6]
中序遍历:[3, 1, 4, 0, 5, 2, 6]
后序遍历:[3, 4, 1, 5, 6, 2, 0]
*/
preorderPrint(head2);
System.out.println();
inorderPrint(head2);
System.out.println();
postorderPrint(head2);
}
/**
* 前序遍历(中左右)
*/
public static void preorderPrint(Node temp){
if(null == temp){
return;
}
System.out.print(temp.value + ",");
preorderPrint(temp.left);
preorderPrint(temp.right);
}
/**
* 中序遍历(左中右)
*/
public static void inorderPrint(Node temp){
if(null == temp){
return;
}
inorderPrint(temp.left);
System.out.print(temp.value + ",");
inorderPrint(temp.right);
}
/**
* 右序遍历(左中右)
*/
public static void postorderPrint(Node temp){
if(null == temp){
return;
}
postorderPrint(temp.left);
postorderPrint(temp.right);
System.out.print(temp.value + ",");
}
public static Node getTreeFromArr2(int[] arr) {
if (arr == null || arr.length == 0) {
return null;
}
LinkedList quque = new LinkedList<>();
Node root = new Node(arr[0]);
quque.add(root);
int index = 1;
while(!quque.isEmpty()){
// pop 0的时候,刚好操作1、2
// pop 1的时候,刚好操作3、4
// pop 2的时候,刚好操作5、6
Node temp = quque.pop();
if(index < arr.length){
temp.left = new Node(arr[index]);
quque.add(temp.left);
index++;
}
if(index < arr.length){
temp.right = new Node(arr[index]);
quque.add(temp.right);
index++;
}
}
return root;
}
/**
* Stack方法
* 前序遍历(中左右)
*/
public static void preorderPrintByStack(Node root) {
Stack stack = new Stack<>();
stack.push(root);
// 可以不用queue,可以直接打印,省空间 N
// 我加一个 queue的目的是为了后序的翻转好理解
Queue queue = new LinkedList<>();
while (!stack.isEmpty()) {
Node temp = stack.pop();
// System.out.print(temp.value + ",");
// 此处可以不打印,直接入一个新的 queue
queue.offer(temp);
if (temp.right != null) {
stack.push(temp.right);
}
if (temp.left != null) {
stack.push(temp.left);
}
}
System.out.print("preorderPrintByStack -> ");
while (!queue.isEmpty()) {
System.out.print(queue.poll().value + ",");
}
System.out.println();
}
/**
* 宽度遍历,其实就是中左右,也就是前序遍历
* 用一个 queue 辅助也是可以搞定的
* @param head
*/
public static void widthPrint(Node head){
if(null == head){
return;
}
Queue queue = new LinkedList<>();
queue.offer(head);
while(!queue.isEmpty()){
Node temp = queue.poll();
System.out.print(temp.value + ",");
if(temp.left != null){
queue.offer(temp.left);
}
if(temp.right != null){
queue.offer(temp.right);
}
}
}
/**
* Stack方法
* 中序遍历(左中右)
*/
public static void inOrderPrintByStack(Node root) {
if(null == root){
return;
}
Node current = root;
Stack stack = new Stack<>();
// 可以不用queue,可以直接打印,省空间 N
// 我加一个 queue的目的是为了后序的翻转好理解
Queue queue = new LinkedList<>();
while (current != null || !stack.isEmpty()) {
// 如果current不是null,那么就一直往左找下去
while(current != null){
stack.push(current);
current = current.left;
}
current = stack.pop();
// System.out.print(current.value + ",");
queue.offer(current);
// 左边已经干完了,那么就一直往右找
current = current.right;
}
System.out.print("inOrderPrintByStack -> ");
while (!queue.isEmpty()) {
System.out.print(queue.poll().value + ",");
}
}
/**
* 右序遍历(左右中)
* 翻过来就是 中右左, 因为前序是中左右,前序是先压right再压left,那么反过来,先压left再压right的话,就会是中右左了
*/
public static void postorderPrintByStack(Node temp) {
if (null == temp) {
return;
}
Stack stackA = new Stack<>();
stackA.push(temp);
// 注意和之前的区别,上面的中序和前序都是 queue ,FIFO,那么 Stack 的FILO,就能实现这个翻转
Stack stackB = new Stack<>();
while(!stackA.isEmpty()){
temp = stackA.pop();
stackB.push(temp);
if(temp.left != null){
stackA.push(temp.left);
}
if(temp.right != null){
stackA.push(temp.right);
}
}
System.out.print("postorderPrintByStack -> ");
while (!stackB.isEmpty()) {
System.out.print(stackB.pop().value + ",");
}
}
@ToString
public static class Node {
public Node left;
public Node right;
public int value;
public Node(int value) {
this.value = value;
}
}
public static void main(String[] args) {
int[] arr = {0, 1, 2, 3, 4, 5, 6};
// Node head = getTreeFromArr(arr);
Node head2 = getTreeFromArr2(arr);
// System.out.println(JSON.toJSONString(head));
System.out.println(JSON.toJSONString(head2));
/*
前序遍历:[0, 1, 3, 4, 2, 5, 6]
中序遍历:[3, 1, 4, 0, 5, 2, 6]
后序遍历:[3, 4, 1, 5, 6, 2, 0]
*/
System.out.println("preorderPrint ->");
preorderPrint(head2);
System.out.println();
System.out.println("inorderPrint ->");
inorderPrint(head2);
System.out.println();
System.out.println("postorderPrint ->");
postorderPrint(head2);
System.out.println();
System.out.println("——————————");
preorderPrintByStack(head2);
inOrderPrintByStack(head2);
postorderPrintByStack(head2);
}
/**
* 前序遍历(中左右)
*/
public static void preorderPrint(Node temp) {
if (null == temp) {
return;
}
System.out.print(temp.value + ",");
preorderPrint(temp.left);
preorderPrint(temp.right);
}
/**
* 中序遍历(左中右)
*/
public static void inorderPrint(Node temp) {
if (null == temp) {
return;
}
inorderPrint(temp.left);
System.out.print(temp.value + ",");
inorderPrint(temp.right);
}
/**
* 右序遍历(左中右)
*/
public static void postorderPrint(Node temp) {
if (null == temp) {
return;
}
postorderPrint(temp.left);
postorderPrint(temp.right);
System.out.print(temp.value + ",");
}
/**
* Stack方法
* 前序遍历(中左右)
*/
public static void preorderPrintByStack(Node root) {
Stack stack = new Stack<>();
stack.push(root);
// 可以不用queue,可以直接打印,省空间 N
// 我加一个 queue的目的是为了后序的翻转好理解
Queue queue = new LinkedList<>();
while (!stack.isEmpty()) {
Node temp = stack.pop();
// System.out.print(temp.value + ",");
// 此处可以不打印,直接入一个新的 queue
queue.offer(temp);
if (temp.right != null) {
stack.push(temp.right);
}
if (temp.left != null) {
stack.push(temp.left);
}
}
System.out.print("preorderPrintByStack -> ");
while (!queue.isEmpty()) {
System.out.print(queue.poll().value + ",");
}
System.out.println();
}
/**
* Stack方法
* 中序遍历(左中右)
*/
public static void inOrderPrintByStack(Node root) {
if(null == root){
return;
}
Node current = root;
Stack stack = new Stack<>();
// 可以不用queue,可以直接打印,省空间 N
// 我加一个 queue的目的是为了后序的翻转好理解
Queue queue = new LinkedList<>();
while (current != null || !stack.isEmpty()) {
// 如果current不是null,那么就一直往左找下去
while(current != null){
stack.push(current);
current = current.left;
}
current = stack.pop();
// System.out.print(current.value + ",");
queue.offer(current);
// 左边已经干完了,那么就一直往右找
current = current.right;
}
System.out.print("inOrderPrintByStack -> ");
while (!queue.isEmpty()) {
System.out.print(queue.poll().value + ",");
}
}
/**
* 右序遍历(左右中)
* 翻过来就是 中右左, 因为前序是中左右,前序是先压right再压left,那么反过来,先压left再压right的话,就会是中右左了
*/
public static void postorderPrintByStack(Node temp) {
if (null == temp) {
return;
}
Stack stackA = new Stack<>();
stackA.push(temp);
// 注意和之前的区别,上面的中序和前序都是 queue ,FIFO,那么 Stack 的FILO,就能实现这个翻转
Stack stackB = new Stack<>();
while(!stackA.isEmpty()){
temp = stackA.pop();
stackB.push(temp);
if(temp.left != null){
stackA.push(temp.left);
}
if(temp.right != null){
stackA.push(temp.right);
}
}
System.out.print("postorderPrintByStack -> ");
while (!stackB.isEmpty()) {
System.out.print(stackB.pop().value + ",");
}
}
public static Node getTreeFromArr2(int[] arr) {
if (arr == null || arr.length == 0) {
return null;
}
LinkedList quque = new LinkedList<>();
Node root = new Node(arr[0]);
quque.add(root);
int index = 1;
while (!quque.isEmpty()) {
// pop 0的时候,刚好操作1、2
// pop 1的时候,刚好操作3、4
// pop 2的时候,刚好操作5、6
Node temp = quque.pop();
if (index < arr.length) {
temp.left = new Node(arr[index]);
quque.add(temp.left);
index++;
}
if (index < arr.length) {
temp.right = new Node(arr[index]);
quque.add(temp.right);
index++;
}
}
return root;
}
深度优先搜索:Depth-First Search (下图打印 0,1,3,4,2,5,6)
广度优先搜索:Breadth-First Search(下图打印 0,1,2,3,4,5,6)
/**
* 构造一棵二叉树
*/
public static Node getNormalTree() {
Node node0 = new Node(0);
Node node1 = new Node(1);
Node node2 = new Node(2);
Node node3 = new Node(3);
Node node4 = new Node(4);
Node node5 = new Node(5);
Node node6 = new Node(6);
node0.left = node1;
node0.right = node2;
node1.left = node3;
node1.right = node4;
node2.left = node5;
node2.right = node6;
return node0;
}
同上面的前序遍历
/**
* breadth First Search
*/
private static void bfsPrint(Node head) {
if (null == head) {
return;
}
System.out.println("bfsPrint ===");
LinkedList queue = new LinkedList<>();
queue.offer(head);
while (!queue.isEmpty()) {
int queueSize = queue.size();
for (int i = 0; i < queueSize; i++) {
Node temp = queue.poll();
System.out.print(temp.value + ", ");
if (temp.left != null) {
queue.offer(temp.left);
}
if (temp.right != null) {
queue.offer(temp.right);
}
}
}
}
/**
* depth First Search
*/
private static void dfsPrint(Node head) {
if (null == head) {
return;
}
System.out.print(head.value + ", ");
dfsPrint(head.left);
dfsPrint(head.right);
}
/**
* depth First Search
*/
private static void dfsPrintByStack(Node head) {
if (null == head) {
return;
}
System.out.println("dfsPrintByStack === ");
Node temp = head;
Stack stack = new Stack<>();
stack.push(temp);
while (!stack.isEmpty()) {
temp = stack.pop();
System.out.print(temp.value + ", ");
if(temp.right != null){
stack.push(temp.right);// 先压入右子树
}
if(temp.left != null){
stack.push(temp.left);// 再压入左子树,确保左子树先出栈
}
}
}
public static Node getSpecialTree() {
Node node0 = new Node(0);
Node node1 = new Node(1);
Node node2 = new Node(2);
Node node3 = new Node(3);
Node node4 = new Node(4);
Node node5 = new Node(5);
Node node6 = new Node(6);
Node node7 = new Node(7);
Node node8 = new Node(8);
Node node9 = new Node(9);
Node node10 = new Node(10);
Node node11 = new Node(11);
node0.left = node1;
node0.right = node2;
node1.left = node3;
node1.right = node4;
node2.left = node5;
node3.left = node6;
node4.left = node7;
node4.right = node8;
node5.right = node9;
node7.left = node10;
node7.right = node11;
return node0;
}
private static void getTreeWidth(Node root) {
System.out.println();
System.out.println("---getTreeWidth---");
Node temp = root;
Queue queue = new LinkedList<>();
queue.offer(temp);
int maxLevelSize = 0;
while (!queue.isEmpty()) {
int levelSize = queue.size();
maxLevelSize = Math.max(maxLevelSize,levelSize);
// 思路就是:for完结束之后,才会进入下一层
for (int i = 0; i < levelSize; i++) {
temp = queue.poll();
System.out.print(temp.value + ",");
if (temp.left != null) {
queue.offer(temp.left);
}
if (temp.right != null) {
queue.offer(temp.right);
}
}
}
System.out.println("maxLevelSize -> " + maxLevelSize);
}
/**
* DFS思想,深度优先检索思想
*/
public static int calculateDepth(Node temp, int depth) {
if (null == temp) {
return depth;
}
// 每次加1层
depth++;
// System.out.print(temp.value);
// 找出left最深
int leftDepth = calculateDepth(temp.left, depth);
// 找出right最深
int rightDepth = calculateDepth(temp.right, depth);
return Math.max(leftDepth, rightDepth);
}
/**
* DFS思想,深度优先检索思想
*/
public static int calculateDepth(Node temp) {
if (null == temp) {
return 0;
}
Stack stack = new Stack<>();
stack.push(temp);
// 记录每个Node对应的层级
Map node2DepthMap = new HashMap<>();
node2DepthMap.put(temp, 1);
while (!stack.isEmpty()) {
temp = stack.pop();
int level = node2DepthMap.get(temp);
// System.out.print(temp.value + ", ");
if (temp.right != null) {
stack.push(temp.right);
node2DepthMap.put(temp.right, level + 1);
}
if (temp.left != null) {
stack.push(temp.left);
node2DepthMap.put(temp.left, level + 1);
}
}
for (int levelCount :
node2DepthMap.values()) {
System.out.println(levelCount);
}
return Collections.max(node2DepthMap.values());
}
/**
* 构造一棵二叉树
*/
public static Node getBSTTree() {
Node node5 = new Node(5);
Node node4 = new Node(4);
Node node7 = new Node(7);
Node node2 = new Node(2);
Node node6 = new Node(6);
Node node8 = new Node(8);
Node node1 = new Node(1);
Node node3 = new Node(3);
node5.left = node4;
node5.right = node7;
node4.left = node2;
node4.right = null;
node2.left = node1;
node2.right = node3;
node7.left = node6;
node7.right = node8;
return node5;
}
思路:采用中序遍历的方法,把原本要print的所有元素,放到queue里面,FIFO,然后判断相邻两个元素大小即可
这个方法需要用到一个 queue 做辅助空间
private static boolean checkBST(Node head) {
LinkedList queue = new LinkedList<>();
// 使用queue辅助空间
checkBSTWithQueue(head, queue);
// 可以打印看看结果
// for (int i = 0; i < queue.size(); i++) {
// System.out.print(queue.get(i).value + ",");
// }
int preNodeValue = queue.poll().value;
while (!queue.isEmpty()){
Node temp = queue.poll();
if(preNodeValue > temp.value){
return false;
}
preNodeValue = temp.value;
}
return true;
}
/**
* 1、如何判断一棵树是不是搜索二叉树?
* 思路:左中右,那么就是中序遍历
*/
private static void checkBSTWithQueue(Node head, Queue queue) {
if (null == head) {
return;
}
//判断左边是不是 BST
checkBSTWithQueue(head.left, queue);
queue.offer(head);
//判断右边是不是 BST
checkBSTWithQueue(head.right, queue);
}
// 说下为什么不用全局变量,这玩意线程不安全
private static int preValue = Integer.MIN_VALUE;
private static class Wrapper{
int value;
Wrapper(int value){
this.value = value;
}
}
private static boolean checkBST(Node head) {
return checkBSTHelper(head,new Wrapper(Integer.MIN_VALUE));
}
/**
* 1、如何判断一棵树是不是搜索二叉树?
* 思路:左中右,那么就是中序遍历
*/
private static boolean checkBSTHelper(Node head, Wrapper preValue) {
if (null == head) {
return true;
}
// 判断左边是不是 BST
if (!checkBSTHelper(head.left, preValue)) {
return false;
}
// System.out.println(head.value); // 这句如果是打印,那么就是 前序遍历输出
// 判断当前
if (preValue.value > head.value) {
return false;
}
// 第一轮,到最左下角的时候,会把值赋给 preValue,作为有意义的第一个值(因为本来中序遍历的逻辑是print这个value)
preValue.value = head.value;
// 判断右边是不是 BST
return checkBSTHelper(head.right, preValue);
}
@AllArgsConstructor
@NoArgsConstructor
private static class BSTReturnData {
private int min;
private int max;
private boolean isBST;
}
private static boolean checkBST3(Node temp) {
if (temp == null) {
return true;
}
return processBST(temp).isBST;
}
private static BSTReturnData processBST(Node temp) {
if (temp == null) {
return new BSTReturnData(Integer.MAX_VALUE, Integer.MIN_VALUE, true);
}
BSTReturnData leftReturnData = processBST(temp.left);
BSTReturnData rightReturnData = processBST(temp.right);
int min = temp.value;
int max = temp.value;
boolean isBST = true;
// BST的要求: left 小于当前,当前小于 right
if (leftReturnData != null) {
min = Math.min(min, leftReturnData.min);
max = Math.max(max, leftReturnData.max);
if(!leftReturnData.isBST || leftReturnData.max >= temp.value){
isBST = false;
}
}
if (rightReturnData != null) {
min = Math.min(min, rightReturnData.min);
max = Math.max(max, rightReturnData.max);
if(!rightReturnData.isBST || rightReturnData.min <= temp.value){
isBST = false;
}
}
return new BSTReturnData(min, max, isBST);
}
/**
* 1、如何判断一棵树是不是搜索二叉树?
* 思路:左中右,那么就是中序遍历
* Stack方法
*/
private static boolean checkBSTHelperWithStack(Node head) {
if (null == head) {
return true;
}
System.out.println(" === checkBSTHelperWithStack ===");
Node current = head;
Stack stack = new Stack<>();
stack.push(current);
int preValue = Integer.MIN_VALUE;
while (!stack.isEmpty()) {
while (current != null && current.left != null) {
stack.push(current.left);
current = current.left;
}
current = stack.pop();
if(preValue > current.value){
return false;
} else {
preValue = current.value;
}
System.out.print(current.value + ", ");
if (current.right != null) {
stack.push(current.right);
}
current = current.right;
}
return true;
}
complete binary tree 完全二叉树
private static boolean isCompleteBinaryTree(Node root) {
if(null == root){
return false;
}
System.out.println();
System.out.println("isCompleteBinaryTree --- begin ---");
System.out.println();
LinkedList queue = new LinkedList<>();
queue.offer(root);
boolean shouldNoChild = false;
while(!queue.isEmpty()){
int queueSize = queue.size();
for (int i = 0; i < queueSize; i++) {
Node temp = queue.poll();
System.out.print(temp.value + ", ");
// 规则1: 有 right 没left,肯定不行
if(temp.left == null && temp.right != null) {
return false;
}
// 规则2: 有 left 没 right,那么之后的节点都必须没有孩子
// 规则3: 没 left 没 right,那么之后的节点也都必须没有孩子
// 那么总结就是只要没 right,之后的节点也都必须没有孩子
if(temp.right == null){
shouldNoChild = true;
}
// 如果后面的节点必须是Leaf节点,那么假如还存在儿子,那肯定有问题
if(shouldNoChild && (temp.left != null || temp.right !=null)){
return false;
}
if(temp.left != null){
queue.offer(temp.left);
}
if(temp.right != null){
queue.offer(temp.right);
}
}
}
System.out.println("isCompleteBinaryTree --- end ---");
return true;
}
balance binary tree 平衡二叉树
平衡的意思就是别两边偏差太严重
1、 left 平衡
2、right 平衡
3、left 与 right的高度差小于等于 1
@NoArgsConstructor
@AllArgsConstructor
private static class BBTReturn {
private boolean isBalance; // 是否平衡
private int height; // 高度
}
/**
* 平衡二叉树
* 1、left 子树必须平衡
* 2、right 子树必须平衡
* 3、left 与 right子树的高度不超过1
*/
private static boolean isBalanceBinaryTree(Node temp) {
return processBalanceBinaryTree(temp).isBalance;
}
private static BBTReturn processBalanceBinaryTree(Node temp) {
if (temp == null) {
return new BBTReturn(true, 0);
}
BBTReturn bbtReturn = new BBTReturn();
BBTReturn leftReturn = processBalanceBinaryTree(temp.left);
BBTReturn rightReturn = processBalanceBinaryTree(temp.right);
bbtReturn.height = Math.max(leftReturn.height, rightReturn.height) + 1;
bbtReturn.isBalance = leftReturn.isBalance && rightReturn.isBalance && Math.abs(leftReturn.height - rightReturn.height) <= 1;
return bbtReturn;
}
@AllArgsConstructor
@NoArgsConstructor
private static class FBTReturnData {
int height; // 树的高度
int nodeNums; // 节点的数量
}
private static boolean isFullBinaryTree(Node temp) {
if (null == temp) {
return true;
}
FBTReturnData returnData = processFBT(temp);
// 满二叉树: 2 ^ 节点高度 - 1 = 节点数量
return Math.pow(2 , returnData.height) - 1 == returnData.nodeNums;
}
private static FBTReturnData processFBT(Node temp) {
if (temp == null) {
return new FBTReturnData(0, 0);
}
FBTReturnData leftRD = processFBT(temp.left);
FBTReturnData rightRD = processFBT(temp.right);
// 节点数量
int nodeNums = leftRD.nodeNums + rightRD.nodeNums + 1;
int height = Math.max(leftRD.height, rightRD.height) + 1;
return new FBTReturnData(height,nodeNums);
}
LowestCommonAncestor 最进共同祖先
public static void testLowestCommonAncestor(){
Node node1 = new Node(1);
Node node2 = new Node(2);
Node node3 = new Node(3);
Node node4 = new Node(4);
Node node5 = new Node(5);
Node node6 = new Node(6);
Node node7 = new Node(7);
node1.left = node2;
node1.right = node3;
node2.left = node4;
node2.right = node5;
node3.left = node6;
node3.right = null;
node6.left = null;
node6.right = node7;
Node lowestCommonAncestor = getLowestCommonAncestor(node1, node7, node3);
System.out.println("lowestCommonAncestor -> " + lowestCommonAncestor.value);
}
/**
* 前提:node1 和 node2 必须在树里面
* 假设每个 Node 的值都不相等
*/
private static Node getLowestCommonAncestor(Node root, Node node1, Node node2) {
if (root == null || node1 == null || node2 == null) {
return null;
}
Map fatherMap = new HashMap<>();
fatherMap.put(root, null);
processLCA(root, fatherMap);
Set node1Fathers = new HashSet<>();
Node node1Father = node1;
while(node1Father != null){
node1Fathers.add(node1Father);
// 递归找爸爸
node1Father = fatherMap.get(node1Father);
}
System.out.println("node1Fathers -> " + JSON.toJSONString(node1Fathers));
Node node2Father = node2;
while(node2Father != null){
if(node1Fathers.contains(node2Father)){
return node2Father;
}
// 递归找爸爸
node2Father = fatherMap.get(node2Father);
}
return null;
}
private static void processLCA(Node temp, Map fatherMap) {
if (null == temp) {
return;
}
if(temp.left != null){
fatherMap.put(temp.left ,temp);
processLCA(temp.left, fatherMap);
}
if(temp.right != null){
fatherMap.put(temp.right ,temp);
processLCA(temp.right, fatherMap);
}
}
看图,套着代码看下,好理解~
private static Node getLowestCommonAncestor2(Node head, Node node1, Node node2) {
// 如果当前节点为空,直接返回 null
if (null == head) {
return head;
}
// 如果当前节点为其中一个目标节点,直接返回该节点
if (head == node1) {
return node1;
}
if (head == node2) {
return node2;
}
Node left = getLowestCommonAncestor2(head.left, node1, node2);
Node right = getLowestCommonAncestor2(head.right, node1, node2);
// 比如叶子节点,如果左右子树返回的节点都为空,说明该节点不包含目标节点,返回 null
if(left == null && right == null){
return null;
}
// 如果左子树返回的节点不为空,右子树返回的节点为空,返回左子树的结果
if(left != null && right == null){
return left;
}
// 如果左子树返回的节点为空,右子树返回的节点不为空,返回右子树的结果
if(left == null && right != null){
return right;
}
// (这是上图的情况二)如果左右子树分别返回了目标节点,说明当前节点是最近的公共祖先节点
return head;
}
假如 Node 有 Parent 指针
private static void testSuccessorNode() {
Node node1 = new Node(1);
Node node2 = new Node(2);
Node node3 = new Node(3);
Node node4 = new Node(4);
Node node5 = new Node(5);
Node node6 = new Node(6);
Node node7 = new Node(7);
node1.left = node2;
node1.right = node3;
node2.left = node4;
node2.right = node5;
node3.left = node6;
node3.right = node7;
node1.parent = null;
node2.parent = node1;
node3.parent = node1;
node4.parent = node2;
node5.parent = node2;
node6.parent = node3;
node7.parent = node3;
/*
1
2 3
4 5 6 7
*/
Node root = node1;
getSuccessorNode(root, node5); // 5的下一个是1
getSuccessorNode(root, node1); // 1的下一个是6
getSuccessorNode(root, node7); // 7的下一个是null
getSuccessorNode(root, node6); // 6的下一个是3
}
private static void getSuccessorNode(Node root, Node target) {
if(root == null || target == null){
return;
}
Node temp = target;
// 规则1 :target 如果有 right 孩子,那么就一直往左下角走
// 比如 Node1
if(temp.right != null){
temp = temp.right;
while(temp.left != null){
temp = temp.left;
}
System.out.println("target -> " + target.value + ", next -> " + temp.value);
return;
} else {
// 规则2:target 如果没有 right,并且他最上面父亲是某个Node的left孩子,那么打印这个Node
// 比如Node5
Node parent = target.parent;
while(parent != null && parent.right == temp){
temp = parent;
parent = temp.parent;
}
// 退出这个 while 循环,要么就是 parent到头了,到root了,要么就是 parent.left == temp
// 属于2情况
if(parent != null){
System.out.println("target -> " + target.value + ", next -> " + parent.value);
return;
} else {
// 规则3,target 如果没有 right,并且他最上面父亲是null,那么他就是最右下角的叶子节点
// 比如Node7
System.out.println("target -> " + target.value + ", next -> " + null);
}
}
}
private static void testSerializeTree() {
Node node1 = new Node(1);
Node node2 = new Node(2);
Node node3 = new Node(3);
node1.left = null;
node1.right = node2;
node2.left = node3;
node2.right = null;
node3.left = null;
node3.right = null;
StringBuilder stringBuilder = new StringBuilder("");
serializeTreePreOrder(node1, stringBuilder);
System.out.println(stringBuilder.toString());
Node head = unSerializeTree(stringBuilder.toString());
System.out.println(head);
}
/**
* 用前序遍历,中左右
*/
private static void serializeTreePreOrder(Node temp, StringBuilder stringBuilder) {
if (temp == null) {
stringBuilder.append("#");
stringBuilder.append(",");
return;
} else {
stringBuilder.append(temp.value);
stringBuilder.append(",");
serializeTreePreOrder(temp.left, stringBuilder);
serializeTreePreOrder(temp.right, stringBuilder);
return;
}
}
private static Node unSerializeTree(String str) {
if(str == null || str.length() == 0){
return null;
}
String[] strArr = str.split(",");
LinkedList queue = new LinkedList<>();
for (int i = 0; i < strArr.length; i++) {
queue.offer(strArr[i]);
}
return unSerializePreOrder(queue);
}
private static Node unSerializePreOrder(LinkedList queue) {
String value = queue.poll();
if(value.equals("#")){
return null;
}
// 1,#,2,3,#,#,#
Node head = new Node(Integer.valueOf(value));
head.left = unSerializePreOrder(queue);
head.right = unSerializePreOrder(queue);
return head;
}
自己拿出一张纸,折叠一次, 要么凹进去,要么吐出来,
折叠1次,折痕1凹进去,写1 凹 (一层,打印 1凹)
折叠2次,折痕1上面的2凹,下面的2凸 (二层,打印 2凹 1凹 2凸)
折叠3次,折痕2上面的3凹,下面的3凸 (三层,打印 3凹 2凹 3凸 1凹 3凹 2凸 3凸)
看右边的二叉树,就是中序遍历的过程。
规律就是,画成二叉树,往左是凹 down,往右走是凸 up
private static void testPrintPaperFloding() {
System.out.println();
System.out.println("=== testPrintPaperFloding ===");
int level = 3; // 层高
printPaperFolding(level);
}
private static void printPaperFolding(int level) {
if (level < 1) {
return;
}
if (level == 1) {
System.out.println("凹");
}
processPaperFolding(level, 1 ,true);
}
private static void processPaperFolding(int totalLevel, int currentLevel ,boolean down) {
if (currentLevel > totalLevel) { // 比如当前是第4层,那么超出3层了,就不打印了
return;
}
processPaperFolding(totalLevel, currentLevel + 1, true);
if(down){
System.out.print(currentLevel + "-" + "凹" + ",");
} else {
System.out.print(currentLevel + "-" + "凸" + ",");
}
processPaperFolding(totalLevel, currentLevel + 1, false);
}
private static void printRight2Left(Node head) {
System.out.println("=== printRight2Left ===");
LinkedList queue = new LinkedList<>();
queue.offer(head);
while (!queue.isEmpty()){
List levelNodeList = new LinkedList<>();
int levelSize = queue.size();
for (int i = 0; i < levelSize; i++) {
Node temp = queue.poll();
// 单纯的打印就是前序遍历
// System.out.print(temp.value + ", ");
if(temp.left != null){
queue.offer(temp.left);
}
if(temp.right != null){
queue.offer(temp.right);
}
levelNodeList.add(temp);
}
System.out.println(levelNodeList.get(levelNodeList.size() - 1).value);
}
}