基础算法之二叉树问题
这里是基础算法系列的第三部分
文章目录
前言
本文章最主要介绍链表的各个问题。
二叉树相关问题
前序,中序,后续遍历
前序
递归
public static void preOrderRecur(Node node){
if (node == null){
return;
}
System.out.print(node.value + " ");
preOrderRecur(node.left);
preOrderRecur(node.right);
}
中前后
无递归
public static void preOrderUnRecur(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 inOrderRecur(Node head) {
if (head == null) {
return;
}
inOrderRecur(head.left);
System.out.print(head.value + " ");
inOrderRecur(head.right);
}
前中后
无递归
public static void inOrderUnRecur(Node head) {
System.out.print("in-order: ");
if (head != null) {
Stack<Node> stack = new Stack<Node>();
while (!stack.isEmpty() || head != null) {
if (head != null) {
stack.push(head);
head = head.left;
} else {
head = stack.pop();
System.out.print(head.value + " ");
head = head.right;
}
}
}
System.out.println();
}
注意:中序,没有右边的概念
后序
递归
public static void posOrderRecur(Node head) {
if (head == null) {
return;
}
posOrderRecur(head.left);
posOrderRecur(head.right);
System.out.print(head.value + " ");
}
前后中
无递归
public static void posOrderUnRecur1(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 int getMaxWidth(Node head) {
if (head == null) {
return 0;
}
int maxWidth = 0;
int curWidth = 0;
int curLevel = 0;
HashMap<Node, Integer> levelMap = new HashMap<>();
levelMap.put(head, 1);
LinkedList<Node> queue = new LinkedList<>();
queue.add(head);
Node node = null;
Node left = null;
Node right = null;
while (!queue.isEmpty()) {
node = queue.poll();
left = node.left;
right = node.right;
if (left != null) {
levelMap.put(left, levelMap.get(node) + 1);
queue.add(left);
}
if (right != null) {
levelMap.put(right, levelMap.get(node) + 1);
queue.add(right);
}
//初始化当前层数
if (levelMap.get(node) > curLevel) {
curWidth = 0;
curLevel = levelMap.get(node);
} else {
curWidth++;
}
maxWidth = Math.max(maxWidth, curWidth);
}
return maxWidth;
}
如何判断一颗二叉树是否是搜索二叉树?
思路:搜索二叉树的特点,在中序遍历下,严格遵守从大到小的顺序。
public static boolean isBST(Node head) {
if (head == null) {
return true;
}
LinkedList<Node> inOrderList = new LinkedList<>();
//中序遍历
process(head, inOrderList);
int pre = Integer.MIN_VALUE;
for (Node cur : inOrderList) {
if (pre >= cur.value) {
return false;
}
pre = cur.value;
}
return true;
}
public static void process(Node node, LinkedList<Node> inOrderList) {
if (node == null) {
return;
}
process(node.left, inOrderList);
inOrderList.add(node);
process(node.right, inOrderList);
}
如何判断是否为完全二叉树
思路:通过层序遍历,然后判断是否出现下面两种情况:
①在出现叶节点情况下,还出现子节点为空
②在左节点为空,右结点不为空,
这些为非完全二叉树情况。
public static boolean isCBT(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);
} else {
leaf = true;
}
}
return true;
}
二叉树题目套路
如何判断是否为平衡二叉树?(二叉树题目套路)
通过递归方式:
①先设定一个终止条件
②对各个分支进行处理
③通过,各个分支返回上来的信息对本层信息进行处理
④返回本层的处理信息。
public static boolean isBalanced(Node head) {
return process(head).isBalanced;
}
public static int levelBalanced(Node head) {
return process(head).height;
}
public static class ReturnType {
public boolean isBalanced;
public int height;
public ReturnType(boolean isB, int hei) {
isBalanced = isB;
height = hei;
}
}
public static ReturnType process(Node x) {
if (x == null) {
return new ReturnType(true, 0);
}
ReturnType leftData = process(x.left);
ReturnType rightData = process(x.right);
int height = Math.max(leftData.height, rightData.height);
boolean isBalanced = leftData.isBalanced && rightData.isBalanced
&& Math.abs(leftData.height - rightData.height) < 2;
return new ReturnType(isBalanced, height);
}
找最小公共祖先结点?(二叉树题目套路)
public static Node lowestAncestor(Node head, Node o1, Node o2) {
//选择终结条件时,就只考虑只有这一个结点。
//
if (head == null || head == o1 || head == o2) {
return head;
}
Node left = lowestAncestor(head.left, o1, o2);
Node right = lowestAncestor(head.right, o1, o2);
//第一种情况两棵树都有返回值,这表明两个结点分散在自己的左右树上。
if (left != null && right != null) {
return head;
}
//若只有一个结点不为Null,则就返回那个,若都为null,则返回null
return left != null ? left : right;
}
在二叉树中找到一个节点的后继节点
全新的Node: 该结构比普通二叉树节点结构多了一个指向父节点的parent指针.
问题:只给一个在二叉树中的某个节点node,请实现返回node的后继节点的函数.
后继结点:在二叉树的中序遍历的序列中, node的下一个节点叫作node的后继节点。
解决思路:后继结点分为两种情况:①此结点有右分支,那么其后继节点在右数的最左结点。② 若此结点没有右分支,那么其后继结点,就要往上找,直到有个结点其左分支是由我们这些结点上来的,那这个结点就是后继结点。否则,没有后继结点。
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.left != 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;
}
二叉树的序列化和反序列化
就是内存里的一棵树如何变成字符串形式,又如何从字符串形式变成内存里的树
如何判断一颗二叉树是不是另一棵二叉树的子树?
折纸问题
请把一段纸条竖着放在桌子上,然后从纸条的下边向上方对折1次,压出折痕后
展开。
此时折痕是凹下去的,即折痕突起的方向指向纸条的背面。
如果从纸条的下边向上方连续对折2次,压出折痕后展开,此时有三条折痕,从
上到下依次是下折痕、下折痕和上折痕。
给定一个输入参数N,代表纸条都从下边向上方连续对折N次。
请从上到下打印所有折痕的方向。
例如:N=1时,打印: down N=2时,打印: down down up
public static void printAllFolds(int N) {
printProcess(1, N, true);
}
public static void printProcess(int i, int N, boolean down) {
if (i > N) {
return;
}
printProcess(i + 1, N, true);
System.out.println(down ? "down " : "up ");
printProcess(i + 1, N, false);
}