1、从上到下打印二叉树I
//从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。
//
//
//
// 例如:
//给定二叉树: [3,9,20,null,null,15,7],
//
// 3
// /
// 9 20
// /
// 15 7
//
//
// 返回:
//
// [3,9,20,15,7]
//
//
//
//
// 提示:
//
//
// 节点总数 <= 1000
//
// Related Topics 树 广度优先搜索 二叉树
二叉树的层序遍历,直接利用队列将左节点和右节点都放入队列,便于读下一层
public int[] levelOrder(TreeNode root) {
Queue<TreeNode> list = new LinkedList<>();
List<Integer> result = new ArrayList<>();
if(root == null){
return new int[0];
}
list.add(root);
while(!list.isEmpty()){
TreeNode node = list.poll();
result.add(node.val);
if(node.left != null){
list.add(node.left);
}
if(node.right != null){
list.add(node.right);
}
}
return result.stream()
.mapToInt(Integer::intValue)
.toArray();
}
2、从上到下打印二叉树
//请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。
//
//
//
// 例如:
//给定二叉树: [3,9,20,null,null,15,7],
//
// 3
// /
// 9 20
// /
// 15 7
//
//
// 返回其层次遍历结果:
//
// [
// [3],
// [20,9],
// [15,7]
//]
//
//
//
//
// 提示:
//
//
// 节点总数 <= 1000
//
// Related Topics 树 广度优先搜索 二叉树
这里要求每一层左右调换顺序,所以不能再依靠队列来做了,我就想使用栈来做,但还是不行,比如:
1
/
2 3
/ \ /
4 5
这个树,当我们将2、3依次入栈后,拿也是从3开始拿,随后将3的右、左节点依次放入栈,那就是2、5,接着拿的就只能是5了,而不能直接拿到2,所以必须使用双向队列来解决这个问题:
public List<List<Integer>> levelOrder(TreeNode root) {
Deque<TreeNode> deque = new LinkedList<>();
List<List<Integer>> res = new ArrayList<>();
if(root != null) deque.add(root);
while(!deque.isEmpty()) {
// 打印奇数层
List<Integer> tmp = new ArrayList<>();
for(int i = deque.size(); i > 0; i--) {
// 从左向右打印
TreeNode node = deque.removeFirst();
tmp.add(node.val);
// 先左后右加入下层节点
if(node.left != null) deque.addLast(node.left);
if(node.right != null) deque.addLast(node.right);
}
res.add(tmp);
if(deque.isEmpty()) break; // 若为空则提前跳出
// 打印偶数层
tmp = new ArrayList<>();
for(int i = deque.size(); i > 0; i--) {
// 从右向左打印
TreeNode node = deque.removeLast();
tmp.add(node.val);
// 先右后左加入下层节点
if(node.right != null) deque.addFirst(node.right);
if(node.left != null) deque.addFirst(node.left);
}
res.add(tmp);
}
return res;
}
3、数字序列中的某一位数字
//数字以0123456789101112131415…的格式序列化到一个字符序列中。在这个序列中,第5位(从下标0开始计数)是5,第13位是1,第19位是4,
//等等。
//
// 请写一个函数,求任意第n位对应的数字。
//
//
//
// 示例 1:
//
// 输入:n = 3
//输出:3
//
//
// 示例 2:
//
// 输入:n = 11
//输出:0
//
//
//
// 限制:
//
//
// 0 <= n < 2^31
//
//
// 注意:本题与主站 400 题相同:https://leetcode-cn.com/problems/nth-digit/
// Related Topics 数学 二分查找
首先需要找到我们这个数处于哪个位数空间,即三位数空间、二位数空间、四位数空间。其次需要找到我们这个数处于这个空间中的哪个数,最后需要知道它处于这个数的哪个位:
public int findNthDigit(int n) {
//知道数字所在的数位
//然后知道它是在哪个范围之内
//然后知道它是在哪个数里面
//然后知道它是这个数的第几位
long count = 9;
long start = 1;
int digit = 1;
while(n > count){
n -= count;
start *= 10;
digit += 1;
count = 9 * start * digit;
}
long num = start + (n-1)/digit;
return Long.toString(num).charAt((n-1)%digit) - '0';
}
4、二叉树的后续遍历
//输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。
//
//
//
// 参考以下这颗二叉搜索树:
//
// 5
// /
// 2 6
// /
// 1 3
//
// 示例 1:
//
// 输入: [1,6,3,2,5]
//输出: false
//
// 示例 2:
//
// 输入: [1,3,2,6,5]
//输出: true
//
//
//
// 提示:
//
//
// 数组长度 <= 1000
//
// Related Topics 栈 树 二叉搜索树 递归 二叉树 单调栈
后序遍历的最后一个数一定是根节点,所以我们直接取最后一个数作为根节点,然后从数组中第一个数出发向后一直遍历,碰到的第一个大于根节点数值的数一定是右子树的左叶子节点,也是右子树子数组的开端,然后从这个点到数组的末尾即我们整棵树的根节点中间的这一段都是右子树子数组的这部分,应该都是大于根节点数值的。同时我们把大问题划分成了子问题,我们只需要判断左子树和右子树的子数组是不是满足条件的。直到最后左右两个端点相等或者左端点下标小于右端点下标就停止判断。
//后序遍历的根节点是最后一个
public boolean verifyPostorder(int[] postorder) {
return recur(postorder, 0, postorder.length-1);
}
private boolean recur(int[] postorder, int i, int j){
//这样说明我们当前判断的长度为0,没有判断的价值
if(i >= j) return true;
int p = i;
//找出第一个大于根节点的数字
while(postorder[p] < postorder[j]) p++;
int m = p;
//找到第一个比根节点小的数字
while(postorder[p] > postorder[j]) p++;
//所以左子树为[i,m-1],右子树为[p+1,j-1].j为根节点
return p == j && recur(postorder, i, m-1) && recur(postorder, m, j-1);
}