二叉树
首先给出二叉树的定义
1 | public class TreeNode { |
1. 你能遍历二叉树吗
树是一种天然的递归结构,因此涉及到树的问题,大多数可以由递归解决。遍历二叉树最形象的就是递归算法。
1 | //前序遍历 |
其他两种遍历方法只需改变函数的调用位置即可。以下设计的主要是非递归算法。这就用到了栈这个数据结构。
1.1 前序遍历
该问题是Leetcode 144
号问题。
1 | public List<Integer> preorderTraversal(TreeNode root) { |
1.2 中序遍历
该问题是Leetcode 94
号问题。
1 | public List<Integer> inorderTraversal(TreeNode root) { |
1.3 后序遍历
这是Leetcode 145
号问题,下面介绍的方法其实是利用栈,模拟了函数递归执行的过程。
1 | public static class Command { |
1.4 层次遍历
层次遍历用到了队列这种数据结构。
1 | public List<Integer> levelOrder(TreeNode root) { |
如果要将每一层的结果保存在一个列表中,该如何?这是Leetcode 102
号问题。
1 | //和层次遍历一样,只不过每次都要保存队列的长度 |
1.5 拓展以及变体
1.5.1 路径总和
这是Leetcode 113
号问题。
1 | /** |
1.5.2 二叉搜索树的最近公共祖先
这是235号问题。 主要利用了二叉树的性质。如果查找的两个结点值一个大于根节点值,一个小于根节点值或等于。那么这两个节点分布在根节点两个子树中,最近的结点就是根节点。
1 | public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { |
1.5.3 二叉树的所有路径
这是Leetcode 257
号问题。
1 | /** |
1.5.4 将有序数组转为二叉搜索树
这是Leetcode 108
号问题。这道题关键在于要求转为平衡二叉树。而二分的思想恰好保证了左右子树高度差不超过1 。因为每次除以2,左右两个数组长度最多相差1。
1 | /** |
1.5.5 验证二叉搜索树
给定一个二叉树,判断其是否是一个有效的二叉搜索树。 这是Leetcode 98
号问题。
1 | //中序遍历的解法,二叉树的中序遍历结果是递增的。 |
1 | //递归解法 在深搜过程中不断替换最大值和最小值,通过比较根节点值和最大值、最小值从而判定 |
1.5.6 二叉树的最近公共祖先
这是Leetcode 236
号问题。
注意:题目给定的是二叉树,不是二叉搜索树。
1 | class Solution { |
1.5.7 二叉树的直径
给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。这是LeetCode 543号问题。
也是二叉树常用的套路,递归解决。
1 | /** |
2. 完全二叉树
2.1 是否是一个完全二叉树
完全二叉树的简单描述就是结点严格按照从上到下、从左到右以此排列,中间不允许出现空结点。因此,算法可以按照定义来编写,利用层次遍历的结果判定。
1 | public static boolean isCBT(TreeNode root) { |
2.2 二叉树的结点个数有多少
这是Leetcode 222
号问题。
1 | private int countLevel(TreeNode p) { |
3. 二叉树的性质
3.1 二叉树的深度(高度)
编写一个函数,求二叉树的深度(最大深度)。这是Leetcode 104
号问题。利用递归的思想可以很简单的写出来。
1 | public int maxDepth(TreeNode root) { |
3.2 是否是一个平衡二叉树
平衡二叉树的定义是任意左右子树高度差不超过1
。因此,会用到求二叉树深度
这个函数。
首先看根节点这棵树左右子树高度差是否超过1,如果是,那么返回false
,否则,递归查看左子树、右子树。
这是Leetcode 110
号问题。
1 | public boolean isBalanced(TreeNode root) { |
3.3 交换二叉树的两个节点
这是Leetcode 226
号问题,反转二叉树。还有一个非常有名的互联网段子。
其实,如果已经掌握了二叉树这种递归结构,可以很快的写出代码。
1 | public TreeNode invertTree(TreeNode root) { |
3.4 对称二叉树
这是Leetcode 101
号问题。
1 | public boolean isSymmetric(TreeNode root) { |
4. 堆
有关堆的详细介绍参见另一篇博客。
4.1 堆排序
堆排序的最坏时间复杂度和平均复杂度都是 $O(nlogn)$,并且不占用额外的空间。
4.2 优先队列
优先队列底层采用了堆实现。优先队列可以有效解决topK
类问题。
采用优先队列的例子,这是Leetcode 451
号问题。
1 | class Solution { |