遍历:
先序遍历:头左右
中序遍历:左头右
后序遍历:左右头
其实他们都是通过递归序来的,每个树每个节点递归序都是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("========");
}
判断两颗树是否结构相同
https://leetcode.com/problems/same-tree
public static class TreeNode {
public int val;
public TreeNode left;
public TreeNode right;
}
public static boolean isSameTree(TreeNode p, TreeNode q) {
//有一个为空 有一个不为空
if (p == null ^ q == null) {
return false;
}
if (p == null && q == null) {
return true;
}
// 都不为空
return p.val == q.val && isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}
判断树是否镜面树
https://leetcode.com/problems/symmetric-tree
public static class TreeNode {
public int val;
public TreeNode left;
public TreeNode right;
}
public static boolean isMirror(TreeNode h1, TreeNode h2) {
if (h1 == null ^ h2 == null) {
return false;
}
if (h1 == null && h2 == null) {
return true;
}
return h1.val == h2.val && isMirror(h1.left, h2.right) && isMirror(h1.right, h2.left);
}
public static boolean isSymmetric(TreeNode root) {
return isMirror(root, root);
}
返回一棵树的最大深度
https://leetcode.com/problems/maximum-depth-of-binary-tree
public static class TreeNode {
public int val;
public TreeNode left;
public TreeNode right;
}
// 以root为头的树,最大高度是多少返回!
public static int maxDepth(TreeNode root) {
if (root == null) {
return 0;
}
return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}
用先序数组和中序数组重建一棵树
https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal
思路:找到头节点 中序的和头节点一样的左边就是左树 右边是右树
代码中g方法和f方法不同在于 g方法有一个map的加速,不用每次遍历查找index
public static class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int val) {
this.val = val;
}
}
//主函数1
public static TreeNode buildTree1(int[] pre, int[] in) {
if (pre == null || in == null || pre.length != in.length) {
return null;
}
return f(pre, 0, pre.length - 1, in, 0, in.length - 1);
}
// 有一棵树,先序结果是pre[L1...R1],中序结果是in[L2...R2]
public static TreeNode f(int[] pre, int L1, int R1, int[] in, int L2, int R2) {
if (L1 > R1) {
return null;
}
//拿到二叉树的头就是先序遍历的第一个
TreeNode head = new TreeNode(pre[L1]);
if (L1 == R1) {
return head;
}
//find从L2开始 直到遇到head停止 那么遇到的都是左树
int find = L2;
while (in[find] != pre[L1]) {
find++;
}
//求左树
head.left = f(pre, L1 + 1, L1 + find - L2, in, L2, find - 1);
//求右树
head.right = f(pre, L1 + find - L2 + 1, R1, in, find + 1, R2);
return head;
}
//主函数2
public static TreeNode buildTree2(int[] pre, int[] in) {
if (pre == null || in == null || pre.length != in.length) {
return null;
}
//统计下中序遍历的值对应的index
HashMap<Integer, Integer> valueIndexMap = new HashMap<>();
for (int i = 0; i < in.length; i++) {
valueIndexMap.put(in[i], i);
}
return g(pre, 0, pre.length - 1, in, 0, in.length - 1, valueIndexMap);
}
// 有一棵树,先序结果是pre[L1...R1],中序结果是in[L2...R2]
public static TreeNode g(int[] pre, int L1, int R1, int[] in, int L2, int R2,
HashMap<Integer, Integer> valueIndexMap) {
if (L1 > R1) {
return null;
}
TreeNode head = new TreeNode(pre[L1]);
if (L1 == R1) {
return head;
}
int find = valueIndexMap.get(pre[L1]);
head.left = g(pre, L1 + 1, L1 + find - L2, in, L2, find - 1, valueIndexMap);
head.right = g(pre, L1 + find - L2 + 1, R1, in, find + 1, R2, valueIndexMap);
return head;
}
二叉树按层遍历并收集节点,逆序打印
https://leetcode.com/problems/binary-tree-level-order-traversal-ii
思路: 遍历,根据size控制树的每一阶多少个,比如第一行就一个进入队列,弹出时候有2个进入了新队列,那么size为2再遍历,都遍历好了,size就是4个了,依次类推,
并且关键用linkList 因为每次都要把新的一个整组放在0的位置
public static class TreeNode {
public int val;
public TreeNode left;
public TreeNode right;
TreeNode(int val) {
this.val = val;
}
}
public List<List<Integer>> levelOrderBottom(TreeNode root) {
List<List<Integer>> ans = new LinkedList<>();
if (root == null) {
return ans;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
int size = queue.size();
List<Integer> curAns = new LinkedList<>();
for (int i = 0; i < size; i++) {
TreeNode curNode = queue.poll();
curAns.add(curNode.val);
if (curNode.left != null) {
queue.add(curNode.left);
}
if (curNode.right != null) {
queue.add(curNode.right);
}
}
ans.add(0, curAns);
}
return ans;
}
判断是否是平衡搜索二叉树
https://leetcode.com/problems/balanced-binary-tree
思路:二叉树递归套路:左边拿到了右边拿到了 一起汇总返回
先来一个平衡二叉树的代码:
public static class TreeNode {
public int val;
public TreeNode left;
public TreeNode right;
TreeNode(int val) {
this.val = val;
}
}
public static class Info {
//是否平衡
public boolean isBalanced;
//高度
public int height;
public Info(boolean i, int h) {
isBalanced = i;
height = h;
}
}
public static boolean isBalanced(TreeNode root) {
return process(root).isBalanced;
}
public static Info process(TreeNode root) {
if (root == null) {
return new Info(true, 0);
}
Info leftInfo = process(root.left);
Info rightInfo = process(root.right);
//我自己就是左右最大的+1
int height = Math.max(leftInfo.height, rightInfo.height) + 1;
//我平衡不平衡就是左右平衡且左右差小于2
boolean isBalanced = leftInfo.isBalanced && rightInfo.isBalanced
&& Math.abs(leftInfo.height - rightInfo.height) < 2;
return new Info(isBalanced, height);
}
再来一个搜索二叉树的代码:
方法1:直接中序遍历
方法2:递归
public static class Info {
//是否为搜索
public boolean isBST;
//此节点最大值
public int max;
//此节点最小值
public int min;
public Info(boolean is, int ma, int mi) {
isBST = is;
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;
if (leftInfo != null) {
max = Math.max(leftInfo.max, max);
min = Math.min(leftInfo.min, min);
}
if (rightInfo != null) {
max = Math.max(rightInfo.max, max);
min = Math.min(rightInfo.min, min);
}
boolean isBST = true;
if (leftInfo != null && !leftInfo.isBST) {
isBST = false;
}
if (rightInfo != null && !rightInfo.isBST) {
isBST = false;
}
boolean leftMaxLessX = leftInfo == null ? true : (leftInfo.max < x.val);
boolean rightMinMoreX = rightInfo == null ? true : (rightInfo.min > x.val);
if (!(leftMaxLessX && rightMinMoreX)) {
isBST = false;
}
return new Info(isBST, max, min);
}
平衡搜索结合下即可
能否组成路径和
https://leetcode.com/problems/path-sum
public static class TreeNode {
public int val;
public TreeNode left;
public TreeNode right;
TreeNode(int val) {
this.val = val;
}
}
public static boolean isSum = false;
public static boolean hasPathSum(TreeNode root, int sum) {
if (root == null) {
return false;
}
isSum = false;
process(root, 0, sum);
return isSum;
}
public static void process(TreeNode x, int preSum, int sum) {
if (x.left == null && x.right == null) {
if (x.val + preSum == sum) {
isSum = true;
}
return;
}
// x是非叶节点
preSum += x.val;
if (x.left != null) {
process(x.left, preSum, sum);
}
if (x.right != null) {
process(x.right, preSum, sum);
}
}
收集达标路径和上一道题的延申
https://leetcode.com/problems/path-sum-ii
public static class TreeNode {
public int val;
public TreeNode left;
public TreeNode right;
TreeNode(int val) {
this.val = val;
}
}
public static List<Integer> copy(List<Integer> path) {
List<Integer> ans = new ArrayList<>();
for (Integer num : path) {
ans.add(num);
}
return ans;
}
public static List<List<Integer>> pathSum(TreeNode root, int sum) {
List<List<Integer>> ans = new ArrayList<>();
if (root == null) {
return ans;
}
ArrayList<Integer> path = new ArrayList<>();
process(root, path, 0, sum, ans);
return ans;
}
public static void process(TreeNode x, List<Integer> path, int preSum, int sum, List<List<Integer>> ans) {
if (x.left == null && x.right == null) {
if (preSum + x.val == sum) {
path.add(x.val);
ans.add(copy(path));
path.remove(path.size() - 1);
}
return;
}
// x 非叶节点
path.add(x.val);
preSum += x.val;
if (x.left != null) {
process(x.left, path, preSum, sum, ans);
}
if (x.right != null) {
process(x.right, path, preSum, sum, ans);
}
path.remove(path.size() - 1);
}