- 实现二叉树的先序、中序、后序遍历(递归方式)
- 实现二叉树的先序、中序、后序遍历(非递归方式)
- 直观的打印一颗二叉树
- 在二叉树中找到一个节点的后继节点(中序遍历的下一个结点为后继结点)
- 在二叉树中找到一个节点的前驱节点(中序遍历的前一个结点为前驱结点)
- 二叉树的序列化和反序列化(先序、层序)
- 判断一棵二叉树是否是平衡二叉树
- 判断一棵树是否是搜索二叉树(递归与非递归)
- 判断一棵树是否是完全二叉树
- 已知一棵完全二叉树,求其节点的个数
- 求最大深度
- 判断是否是对称二叉树
- 求最小深度
- 求二叉搜索树相邻结点绝对值的最小差值
- 求所有从根节点到叶子节点的路径
- 最近公共祖先
- 二叉搜索树的范围和
- 二叉树的层序遍历
- 二叉树的锯齿形层序遍历
- 翻转二叉树
1.实现二叉树的先序、中序、后序遍历(递归方式)
先序
private static void preOrder(Node nodeHead) {
if (nodeHead == null){
return;
}
//在第一次访问该结点的时候打印
System.out.println(nodeHead.value);
preOrder(nodeHead.left);
preOrder(nodeHead.right);
}
中序
private static void inOrder(Node nodeHead) {
if (nodeHead == null){
return;
}
inOrder(nodeHead.left);
//在第二访问该结点的时候打印
System.out.println(nodeHead.value);
inOrder(nodeHead.right);
}
后序
private static void posOrder(Node nodeHead) {
if (nodeHead == null){
return;
}
posOrder(nodeHead.left);
posOrder(nodeHead.right);
System.out.println(nodeHead.value);
//在第三次访问该结点的时候打印
}
2.实现二叉树的先序、中序、后序遍历(非递归方式)
先序
思路:
(1)用栈实现
(2)先将头结点压入栈
(3)如果栈不为空,弹出栈顶并打印该结点;如果该结点有右孩子就先压右孩子;
如果该结点有左孩子就再压左孩子
(4)重复步骤(3)
private static void preOrder(Node nodeHead) {
if (nodeHead != null){
Stack<Node> stack = new Stack<>();
//先压入头结点
stack.push(nodeHead);
while (!stack.isEmpty()){
//弹出栈顶
nodeHead = stack.pop();
System.out.println(nodeHead.value);
//有右孩子先压右孩子
if (nodeHead.right != null){
stack.push(nodeHead.right);
}
//有左孩子再压左孩子
if (nodeHead.left != null){
stack.push(nodeHead.left);
}
}
}
}
中序
思路:
(1)用栈实现
(2)如果当前Node!=null,压入Node,指针指向Node左孩子
(3)如果当前Node==null,弹出栈顶打印,指针指向Node右孩子
private static void inOrder(Node nodeHead) {
if (nodeHead != null){
Stack<Node> stack = new Stack<>();
while (!stack.isEmpty() || nodeHead != null){
//左孩子不为空就压自己 指针指向左孩子
if (nodeHead != null){
stack.push(nodeHead);
nodeHead = nodeHead.left;
}else {
//没左孩子 弹出栈顶 并压栈顶的右孩子
nodeHead = stack.pop();
System.out.println(nodeHead.value);
nodeHead = nodeHead.right;
}
}
}
}
后序
思路:
(1)用两个栈 栈1和栈2
(2)先将头结点压入栈1
(3)如果栈1不为空,弹出栈1顶放进栈2;
栈1顶如果有左孩子就往栈1压入左孩子;
栈1顶如果有右孩子再往栈1压入右孩子
(4)重复步骤(3)
(5)栈1为空时,挨个打印栈2
private static void posOrder(Node head){
if (head != null){
Stack<Node> stack1 = new Stack<>();
Stack<Node> stack2 = new Stack<>();
//先压入头结点
stack1.push(head);
while (!stack1.isEmpty()){
head = stack1.pop();
//该打印时不打印 压入stack2
stack2.push(head);
//有左孩子压左孩子 -> 最终栈2里是逆序打印,所以跟先序打印反过来,先压左孩子再压右孩子
if (head.left != null){
stack1.push(head.left);
}
//有右孩子再压右孩子
if (head.right != null){
stack1.push(head.right);
}
}
//最终挨个打印栈2
while (!stack2.isEmpty()){
System.out.println(stack2.pop().value);
}
}
}
3.直观的打印一颗二叉树
不是面试/笔试题 -> 用于自己来判断二叉树的结构是否正确
public class printTree27 {
public static void main(String[] args) {
Node nodeHead = getNodeHead();
printTree(nodeHead);
}
public static void printTree(Node head) {
System.out.println("Binary Tree:");
printInOrder(head, 0, "H", 17); //占用长度为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();
}
private static Node getNodeHead() {
Node head = new Node(0);
Node node1 = new Node(1);
head.left = node1;
Node node2 = new Node(2);
head.right = node2;
Node node3 = new Node(3);
node1.left = node3;
Node node4 = new Node(4);
node1.right = node4;
Node node5 = new Node(5);
node2.left = node5;
return head;
}
public static class Node{
public int value;
public Node left;
public Node right;
public Node(int value){
this.value = value;
}
}
}
4.在二叉树中找到一个节点的后继节点(中序遍历的下一个结点为后继结点)
思路:
(1)如果该结点node有右孩子,那么node的后继结点一定的其右子数的最左孩子
(2)如果该结点node没有右孩子,就找该结点的父结点parent ->
(3)如果该结点node的父结点parent的左孩子就是该结点node,那么node的后继结点就是parent
(4)如果该结点的结点parent的左孩子不是该结点node,则node,parent同时上移,重复步骤(3)
private static Node inBinaryTreeGetNextNode(Node node){
//记录父结点
Node parent = null;
//判空
if (node == null){
return null;
}
//如果有右孩子 就是右孩子为子树头结点的树中,最左孩子
if (node.right != null){
parent = getLeftMost(node.right);
}else {
//如果没有右孩子 找父结点
parent = node.parent;
while (parent != null) {
//如果当前结点是父结点的左孩子 那么父结点就是后继结点
if (parent.left == node){
break;
}else {
//如果当前结点是父结点的右孩子 那么继续往上找
node = parent;
parent = node.parent;
}
}
}
return parent;
}
private static Node getLeftMost(Node node){
if (node.left == null){
return node;
}
while (node.left != null){
node = node.left;
}
return node;
}
//时间 76.39
//空间 51.08
private boolean hasVisit;
public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
hasVisit = false;
return dfs(root, p);
}
public TreeNode dfs(TreeNode node, TreeNode p) {
if (node == null) return null;
// 遇到目标节点就将访问标记置为true
if (node == p) hasVisit = true;
TreeNode left = dfs(node.left, p);
if (hasVisit && node.val > p.val) {
// 第一次满足if时,当前节点就是答案
// 之后的就不是直接后继了,所以将访问标记置为false
hasVisit = false;
return node;
}
TreeNode right = dfs(node.right, p);
return left == null ? right : left;
}
5.在二叉树中找到一个节点的前驱节点(中序遍历的前一个结点为前驱结点)
思路:
(1)如果该结点node有左孩子,那么node的前驱结点一定是其左子树的最右孩子
(2)如果该结点node没有右孩子,就找该结点的父结点parent ->
(3)如果该结点node的parent的右孩子就是node,那么那么parent就是node的前驱结点
(4)如果该结点node的parent的右孩子不是node,node,parent同时上移,重复步骤(3)
private static Node inBinaryTreeGetNextNode(Node node){
//记录父结点
Node parent = null;
//判空
if (node == null){
return null;
}
//如果有右孩子 就是右孩子为子树头结点的树中,最左孩子
if (node.right != null){
parent = getRightMost(node.right);
}else {
//如果没有右孩子 找父结点
parent = node.parent;
while (parent != null) {
//如果当前结点是父结点的右孩子 那么父结点就是前驱结点
if (parent.right == node){
break;
}else {
//如果当前结点是父结点的右孩子 那么继续往上找
node = parent;
parent = node.parent;
}
}
}
return parent;
}
private static Node getLeftMost(Node node){
if (node.left == null){
return node;
}
while (node.left != null){
node = node.left;
}
return node;
}
6二叉树的序列化和反序列化
先序序列化
思路:
(1)递归
(2)如果当前结点为空,返回 #_
(3)如果当前结点不为null,返回 value+_ ,遍历左子树,再遍历右子数
private static String serialBinaryTreeByPre(Node head){
String returnString = "";
//判空
if (head == null){
return "#_";
}
returnString = head.value + "_";
returnString = returnString + serialBinaryTreeByPre(head.left);
returnString = returnString + serialBinaryTreeByPre(head.right);
return returnString;
}
先序反序列化
思路:
(1)先将Sting按照_分解
(2)将分解得到的数据依次添加进队列
(3)队列进行递归
(4)弹出头结点,如果头结点为null,返回null
(5)头结点不为null,遍历左子树,再遍历右子树
//先序反序列化
private static Node reconByPre(String tree){
//判空
if (tree == null){
return null;
}
Queue<String> queue = new LinkedList<>();
//分解
String[] split = tree.split("_");
for (int i = 0;i < split.length;i++){
queue.offer(split[i]);
}
return reconPreOrder(queue);
}
//先序反序列化
public static Node reconPreOrder(Queue<String> queue) {
String poll = queue.poll();
if (poll.equals("#")){
return null;
}
Node head = new Node(Integer.parseInt(poll));
head.left = reconPreOrder(queue);
head.right = reconPreOrder(queue);
return head;
}
层序序列化
思路
- 将头结点压入队列
- while循环判断-> 依次从队列弹出头结点->如果结点为null或者不为null,字符串标记
- 如果该结点左孩子不为空,压入左孩子,如果左孩子为空,压入null作为标记
- 如果该结点右孩子不为空,压入右孩子,如果右孩子为空,压入null作为标记
//层序序列化
private static String serialBinaryTreeByLevel(Node head){
//判空
if (head == null){
return "#_";
}
String returnString ="";
Queue<Node> queue = new LinkedList<>();
//将头结点压入
queue.offer(head);
while (!queue.isEmpty()){
head = queue.poll();
if (head == null){
returnString = returnString + "#_";
}else {
returnString = returnString + head.value + "_";
//左孩子不为空则压入左孩子 否则压入一个null为标记
if (head.left != null){
queue.offer(head.left);
}else {
queue.offer(null);
}
//右孩子不为空则压入右孩子 否则压入一个null为标记
if (head.right != null){
queue.offer(head.right);
}else {
queue.offer(null);
}
}
}
return returnString;
}
层序反序列化
思路:
(1)先将字符串结构
(2)用指针标记数组,将第一个结点压入队列
(3)while循环
(4)得到头结点左孩子,如果不为空则压入队列
(5)得到头结点右孩子,如果不为空则压入队列
//层序反序列化
private static Node reconByLevel(String tree){
//判空
if (tree == null || tree.equals("#_")){
return null;
}
String[] split = tree.split("_");
//记录下标
int curNum = 0;
//创建头结点
Node head = generatedNode(split[curNum++]);
//创建当前结点
Node curNode = head;
//创建队列
Queue<Node> queue = new LinkedList<>();
//压入头结点
queue.offer(curNode);
while (!queue.isEmpty()){
curNode = queue.poll();
curNode.left = generatedNode(split[curNum++]);
curNode.right = generatedNode(split[curNum++]);
if (curNode.left != null){
queue.offer(curNode.left);
}
if (curNode.right != null){
queue.offer(curNode.right);
}
}
return head;
}
private static Node generatedNode(String string){
if (string.equals("#")){
return null;
}
return new Node(Integer.parseInt(string));
}
7.判断一棵二叉树是否是平衡二叉树
思路:
(1)创建新类保存信息:树的高度和是否是平衡树
(2)递归
(3)递归左孩子,如果为不平衡树,返回false
(4)递归右孩子,如果为不平衡树,返回false
(5)判断左子树右子树的高度,如果为不平衡树,返回false
(6)返回左子树和右子树最大高度+1,true
//定义返回类型类
private static class returnClass{
int height;
boolean isBalance;
public returnClass(int height, boolean isBalance) {
this.height = height;
this.isBalance = isBalance;
}
}
private static returnClass isBalanceBinaryTree(Node head){
//判空
if (head == null){
return new returnClass(0,true);
}
returnClass leftTree = isBalanceBinaryTree(head.left);
if (!leftTree.isBalance){
return new returnClass(0,false);
}
returnClass rightTree = isBalanceBinaryTree(head.right);
if (!rightTree.isBalance){
return new returnClass(0,false);
}
if (Math.abs(leftTree.height - rightTree.height) > 1){
return new returnClass(0,false);
}
return new returnClass(Math.max(leftTree.height,rightTree.height)+1,true);
}
8.判断一棵树是否是搜索二叉树
非递归
思路:
(1)中序遍历应该按中小到大排序
private static boolean isBST(Node head){
//判空
if (head == null){
return true;
}
Stack<Node> stack = new Stack<>();
long value = Integer.MIN_VALUE;
boolean isBST = true;
while (!stack.isEmpty() || head != null){
if (head != null){
stack.push(head);
head = head.left;
}else {
head = stack.pop();
if (value < head.value){
value = head.value;
}else {
isBST = false;
break;
}
head = head.right;
}
}
return isBST;
}
递归
//递归
static long pre = Long.MIN_VALUE;
static boolean isBST = true;
//递归
public static void isValidBST(Node root) {
//判空
if (root == null){
return;
}
isValidBST(root.left);
if (pre < root.value){
pre = root.value;
}else {
isBST = false;
}
isValidBST(root.right);
}
9.判断一棵树是否是完全二叉树
思路:
(1)层序遍历
(2)如果没有左孩子,有右孩子一定不是完全二叉树
(3)如果遇到了有左孩子,没有右孩子的情况,之后再遇到一定不是完全二叉数
(3)遇到了有左孩子,没有右孩子的情况标记
private static boolean isCST(Node head){
//判空
if (head == null){
return true;
}
Queue<Node> queue = new LinkedList<>();
queue.offer(head);
//标记是否遇到过叶结点
boolean havedLeft = false;
while (!queue.isEmpty()){
head = queue.poll();
//如果有右孩子而没有左孩子那么一定不是搜索二叉树 或者 遇到了叶结点之后还遇到了非叶结点
if ((head.left == null && head.right != null) || (havedLeft && head.left != null)){
return false;
}
//左孩子不为空 压入队列
if (head.left != null){
queue.offer(head.left);
}
//右孩子不为空 压入队列
if (head.right != null){
queue.offer(head.right);
}
//如果左孩子为空 右孩子不为空 那么遇到了叶结点 只可能遇见一次叶结点
if (head.left != null && head.right == null){
havedLeft = true;
}
}
return true;
}
10.已知一棵完全二叉树,求其节点的个数
思路:
(1)递归
(2)如果该结点右子树最左结点碰到最底,那么左子树为满二叉树,右子树继续递归
(3)如果该结点右子树最左结点没有碰到最底,那么右子树为满二叉树,左子树继续递归
private static int isCSTAndNodeNum(Node head){
//判空
if (head == null){
return 0;
}
return getNodeNum(head, 1, mostLeftLevel(head,1));
}
private static int getNodeNum(Node head,int level,int height){
if (height == level){
return 1;
}
//如果该结点的右子树最左结点碰到该树深度 -> 那么该结点左子树为满二叉树 -> 右子树继续递归
if (mostLeftLevel(head.right,level + 1) == height){
return (1<< (height-level)) + getNodeNum(head.right,level + 1,height);
}else {
//如果该结点的右子树最左结点没有碰到该树深度 -> 那么该结点右子树为满二叉树 (高度-1) -> 左子树继续递归
return (1<< (height - level - 1)) + getNodeNum(head.left,level + 1,height);
}
}
private static int mostLeftLevel(Node node,int level){
while (node != null){
node = node.left;
level++;
}
return level - 1;
}
11.求最大深度
题目:
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
//时间 100
//空间 42
//深度优先
public int maxDepth_recursion(TreeNode root) {
if (root == null){
return 0;
}
int left = maxDepth_recursion(root.left);
int right = maxDepth_recursion(root.right);
return Math.max(left,right) + 1;
}
//时间 17.79
//空间 29.04
//广度优先
public int maxDepth_NoRecursion(TreeNode root) {
if (root == null){
return 0;
}
//队列维护一层所有结点
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
int res = 0;
while (!queue.isEmpty()){
int size = queue.size();
while (size > 0){
TreeNode poll = queue.poll();
if (poll.left != null){
queue.offer(poll.left);
}
if (poll.right != null){
queue.offer(poll.right);
}
size--;
}
res++;
}
return res;
}
12.判断是否是对称二叉树
题目:给定一个二叉树,检查它是否是镜像对称的。
//时间 27.49
//空间 5.09
public boolean isSymmetric(TreeNode root) {
if (root == null){
return true;
}
return check_Norecursion(root.left,root.right);
}
public boolean check_Norecursion(TreeNode left, TreeNode right) {
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(left);
queue.offer(right);
while (!queue.isEmpty()){
TreeNode poll1 = queue.poll();
TreeNode poll2 = queue.poll();
if (poll1 == null && poll2 == null){
continue;
}
//只剩 都不为空 或者 只有一个为空 的情况
if ((poll1 == null || poll2 == null) ||( poll1.val != poll2.val)){
return false;
}
queue.offer(poll1.left);
queue.offer(poll2.right);
queue.offer(poll1.right);
queue.offer(poll2.left);
}
return true;
}
//时间 100
//空间 76
public boolean isSymmetric(TreeNode root) {
if (root == null){
return true;
}
return check_Recursion(root.left,root.right);
}
public boolean check_Recursion(TreeNode left, TreeNode right) {
if (left == null && right == null){
return true;
}
//只剩 有一个为空 或者 都不为空 的情况
if (left == null || right == null){
return false;
}
return (left.val == right.val) &&
check_Recursion(left.right,right.left) &&
check_Recursion(left.left,right.right);
}
13.求最小深度
题目:
最小深度是从根节点到最近叶子节点的最短路径上的节点数量
public int minDepth(TreeNode root) {
if (root == null){
return 0;
}
return count_Recursion(root);
}
//时间 62
//空间 27
//递归
public int count_Recursion(TreeNode root){
if (root == null){
return Integer.MAX_VALUE;
}
if (root.left == null && root.right == null){
return 1;
}
int left = count_Recursion(root.left);
int right = count_Recursion(root.right);
return Math.min(left,right) + 1;
}
public int minDepth(TreeNode root) {
if (root == null){
return 0;
}
return count_Guang(root);
}
//时间 99.77
//空间 79.84
//广度遍历
public int count_Guang(TreeNode root){
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
int res = 0;
int size = 1;
boolean isLeft = false;
while (!queue.isEmpty()){
size = queue.size();
while (size > 0){
TreeNode poll = queue.poll();
if (poll.left == null && poll.right == null){
isLeft = true;
break;
}
if (poll.left != null){
queue.offer(poll.left);
}
if (poll.right != null){
queue.offer(poll.right);
}
size--;
}
res++;
if (isLeft){
break;
}
}
return res;
}
14.求二叉搜索树相邻结点绝对值的最小差值
题目:给你一棵所有节点为非负值的二叉搜索树,请你计算树中任意两节点的差的绝对值的最小值
static int res = Integer.MAX_VALUE;
static int pre = 0;
static boolean isFirst = true;
//时间 100
//空间 64.72
public static int minDiffInBST_Recursion(TreeNode root){
if (root == null){
return 0;
}
count(root);
return res;
}
public static void count(TreeNode root) {
if (root == null){
return;
}
count(root.left);
if (isFirst){
pre = root.val;
isFirst = false;
}else {
res = Math.min(res, Math.abs(pre - root.val));
pre = root.val;
}
count(root.right);
}
//时间 100
//空间 11
public static int minDiffInBST_NoRecursion(TreeNode root) {
if (root == null){
return 0;
}
Stack<TreeNode> stack = new Stack<>();
int res = Integer.MAX_VALUE;
int pre = 0;
boolean isFirst = true;
while (!stack.isEmpty() || root != null){
if (root != null){
stack.push(root);
root = root.left;
}else {
root = stack.pop();
if(isFirst){
pre = root.val;
isFirst = false;
}else {
res = Math.min(res, Math.abs(pre - root.val));
pre = root.val;
}
root = root.right;
}
}
return res;
}
15.求所有从根节点到叶子节点的路径
题目:
给定一个二叉树,返回所有从根节点到叶子节点的路径
//时间 39.21
//空间 23.21
public List<String> binaryTreePaths(TreeNode root) {
List<String> list = new ArrayList<>();
constructPaths(root,"",list);
return list;
}
public void constructPaths(TreeNode root, String path, List<String> paths) {
if (root == null){
return;
}
constructPaths(root.left,path + root.val + "->",paths);
constructPaths(root.right,path + root.val + "->",paths);
if (root.left == null && root.right == null){
paths.add(path + root.val);
}
}
16.最近公共祖先
题目:
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先
//时间 20.90
//空间 5.62
//记录所有 【左\右子节点的值,当前结点】
Map<Integer,TreeNode> parents = new HashMap<>();
Set<Integer> visited = new HashSet<>();
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
write(root);
while (p != null){
visited.add(p.val);
p = parents.get(p.val);
}
while (q != null){
if (visited.contains(q.val)){
return q;
}
q = parents.get(q.val);
}
return null;
}
public void write(TreeNode root){
if (root.left != null){
parents.put(root.left.val,root);
write(root.left);
}
if (root.right != null){
parents.put(root.right.val,root);
write(root.right);
}
}
//时间 100
//空间 32.23
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == q || root == p){
return root;
}
if (root != null){
TreeNode treeNodeLeft = lowestCommonAncestor(root.left, p, q);
TreeNode treeNodeRight = lowestCommonAncestor(root.right, p, q);
if (treeNodeLeft != null && treeNodeRight != null){
return root;
}else if (treeNodeLeft == null){
return treeNodeRight;
}else {
return treeNodeLeft;
}
}
return null;
}
//时间 100
//空间 77.52
TreeNode res = null;
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
dfs(root, p, q);
return res;
}
public boolean dfs(TreeNode root, TreeNode p, TreeNode q){
if (root == null){
return false;
}
boolean left = dfs(root.left, p, q);
boolean right = dfs(root.right, p, q);
if (((root.val == q.val || root.val == p.val) && (left || right)) || (left && right)){
res = root;
}
return left || right || (root.val == q.val || root.val == p.val);
}
17.二叉搜索树的范围和
题目:给定二叉搜索树的根结点 root,返回值位于范围 [low, high] 之间的所有结点的值的和。
//时间 53
//空间 73
int res = 0;
public int rangeSumBST_Recursion(TreeNode root, int low, int high) {
if (root == null){
return 0;
}
count(root,low,high);
return res;
}
public void count(TreeNode root, int low, int high) {
if (root == null){
return;
}
count(root.left,low,high);
if (low <= root.val && root.val <= high){
res += root.val;;
}
count(root.right,low,high);
}
//时间 7.26
//空间 68.97
public int rangeSumBST_NoRecursion(TreeNode root, int low, int high) {
int res = 0;
Stack<TreeNode> stack = new Stack<>();
while (!stack.isEmpty() || root != null){
if(root != null){
stack.push(root);
root = root.left;
}else {
root = stack.pop();
res = low <= root.val && root.val <= high ? res + root.val : res;
root = root.right;
}
}
return res;
}
18.二叉树的层序遍历
题目:
给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
//时间 93.89
//空间 25.04
public static List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> listRes = new ArrayList<>();
if (root == null){
return listRes;
}
Queue<TreeNode> queue1 = new LinkedList<>();
Queue<TreeNode> queue2 = new LinkedList<>();
queue1.offer(root);
while (!queue1.isEmpty()){
levelCount(listRes,queue1,queue2);
Queue<TreeNode> tmp = null;
tmp = queue1;
queue1 = queue2;
queue2 = tmp;
}
return listRes;
}
public static void levelCount(List<List<Integer>> listRes,Queue<TreeNode> queue1,Queue<TreeNode> queue2){
List<Integer> list = new ArrayList<>();
while (!queue1.isEmpty()){
TreeNode poll = queue1.poll();
list.add(poll.val);
System.out.println("poll.val = " + poll.val);
if (poll.left != null){
queue2.offer(poll.left);
}
if (poll.right != null){
queue2.offer(poll.right);
}
}
listRes.add(list);
}
//时间 93.89
//空间 17.22
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> listRes = new ArrayList<>();
if (root == null){
return listRes;
}
Queue<TreeNode> queue1 = new LinkedList<>();
queue1.offer(root);
while (!queue1.isEmpty()){
List<Integer> list = new ArrayList<>();
int size = queue1.size();
for (int i = 0; i < size; i++) {
TreeNode poll = queue1.poll();
list.add(poll.val);
if (poll.left != null){
queue1.offer(poll.left);
}
if (poll.right != null){
queue1.offer(poll.right);
}
}
listRes.add(list);
}
return listRes;
}
19.二叉树的锯齿形层序遍历
题目:
给定一个二叉树,返回其节点值的锯齿形层序遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。
//时间 97.37
//空间 30.28
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> listRes = new ArrayList<>();
if (root == null){
return listRes;
}
Stack<TreeNode> stack1 = new Stack<>();
Stack<TreeNode> stack2 = new Stack<>();
stack1.push(root);
boolean isSingle = true;
while (!stack1.isEmpty()){
int size = stack1.size();
List<Integer> list = new ArrayList<>();
//如果当前层数是单数 -> 先压左再压右
if (isSingle){
for (int i = 0; i < size; i++) {
root = stack1.pop();
list.add(root.val);
if (root.left != null){
stack2.push(root.left);
}
if (root.right != null){
stack2.push(root.right);
}
}
Stack<TreeNode> tmp = null;
tmp = stack2;
stack2 = stack1;
stack1 = tmp;
isSingle = false;
}else {
//如果当前层数是双数 -> 先压右再压左
for (int i = 0; i < size; i++) {
root = stack1.pop();
list.add(root.val);
if (root.right != null){
stack2.push(root.right);
}
if (root.left != null){
stack2.push(root.left);
}
}
Stack<TreeNode> tmp = null;
tmp = stack2;
stack2 = stack1;
stack1 = tmp;
isSingle = true;
}
listRes.add(list);
}
return listRes;
}
//时间 97.37
//空间 5.18
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> ans = new LinkedList<List<Integer>>();
if (root == null) {
return ans;
}
Queue<TreeNode> nodeQueue = new LinkedList<TreeNode>();
nodeQueue.offer(root);
boolean isOrderLeft = true;
while (!nodeQueue.isEmpty()) {
Deque<Integer> levelList = new LinkedList<Integer>();
int size = nodeQueue.size();
for (int i = 0; i < size; ++i) {
TreeNode curNode = nodeQueue.poll();
if (isOrderLeft) {
levelList.offerLast(curNode.val);
} else {
levelList.offerFirst(curNode.val);
}
if (curNode.left != null) {
nodeQueue.offer(curNode.left);
}
if (curNode.right != null) {
nodeQueue.offer(curNode.right);
}
}
ans.add(new LinkedList<Integer>(levelList));
isOrderLeft = !isOrderLeft;
}
return ans;
}
20.翻转二叉树
//时间100
//空间72.97
public TreeNode invertTree(TreeNode root) {
if (root == null){
return null;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()){
TreeNode poll = queue.poll();
TreeNode tmp = poll.left;
poll.left = poll.right;
poll.right = tmp;
if (poll.left != null){
queue.offer(poll.left);
}
if (poll.right != null){
queue.offer(poll.right);
}
}
return root;
}
//时间100
//空间97.75
public TreeNode invertTree_Re(TreeNode root) {
if (root == null){
return null;
}
TreeNode tmp = root.right;
root.right = root.left;
root.left = tmp;
invertTree_Re(root.left);
invertTree_Re(root.right);
return root;
}