102. 二叉树的层序遍历
解题思路:
-
1. BFS广度优先遍历 ,使用队列,按层访问
解题思路:
-
2. 前序遍历 , 递归 ,在递归方法参数中,将 层索引 和 节点 一起向下传递,这样当每次递归访问根节点时,就能拿到对应节点所属的 层索引 ,就知道添加到哪一层的结果集中了。
-
注意:当 结果集大小==层索引 时,添加一个 新的集合 ,否则 res.get(level) 时会越界异常。
解题思路:
-
3. 前序遍历 , 迭代 ,在压栈时,将 节点 和 对应的层索引 一并 压栈 ,在出栈时拿到节点和对应的层索引,就知道添加到哪一层的结果集中了。
-
注意:当 结果集大小==层索引 时,添加一个 新的集合 ,否则 res.get(level) 时会越界异常。
103. 二叉树的锯齿形层序遍历
解题思路:
-
1. BFS广度优先遍历 , 同102题,可以记录层索引 level , 使用双端队列 LinkedList 收集每一层的节点, level 为 奇数 时在 头部 添加,否则就在 尾部 添加(level从0开始)。或者也可以使用一个 标记位 ,每层 反向 一下 标记位 即可。或者,也可以先按正常层序遍历收集结果,完了再对结果进行处理。
解题思路:
-
2. 前序遍历 , 递归 , 同102题, 在递归方法参数中,将 层索引 和 节点 一起向下传递, 使用双端队列 LinkedList 收集每一层的节点, 当 level 为 奇数 时在 头部 添加,否则就在 尾部 添加。(level从0开始)
199. 二叉树的右视图
解题思路:
-
1. BFS 层序遍历 ,每次取出 当前层的大小 ,然后遍历这一层,在收集答案时只收集当前层的 最后一个节点 。
解题思路:
-
2. DFS 前序遍历的变形 ,同102.递归时向下传递 层索引level ,先递归访问 右子树 ,再递归访问 左子树 ,当 结果集合大小等于level 时,收集 当前访问的节点 值,就是 右视图 中当前层的 第一个 节点。
515. 在每个树行中找最大值
解题思路:
-
BFS 层序遍历 同102, 记录 访问每一层中的最大值即可。
297. 二叉树的序列化与反序列化
解题思路:
-
1. 序列化 使用 BFS层序遍历 ,以 逗号 拼接, 空树 以 null 字符串拼接 (注意: 由于需要处理空节点,所以左右子树为 null 时,也要 入队 一次 ) ,
-
在 反序列化 时,将 字符串按逗号分割 保 存到一个 结果 队列list 中, 先 从中取 第一个字符串 构造出 根节点 ,然后加入 队列 ,接下来按照 BFS 层序遍历的方式循环构造 左右子树 , 每次从队列取出 根节点 ,同时从 结果 队列list 中取出它的 左右子树对应的 字符串 ,如果不为 null 字符串 就转成 整型 创建出 树节点 挂到 当前根节点 上,并继续将创建出的左右子树入队 。 最后返回创建出的根节点即可。
注意:这里
要入队空节点,必须使用
LinkedList
来创建队列,使用
ArrayDeque
不行,在入队空节点时会报空指针异常。或者更麻烦一点的写法可以使用
Queue<Object>
在入队时将
“null”
入队,出队时再另做判断。
这里相当于结果字符串转换成一个参照列表,然后使用另一个队列在这个参照列表上面执行BFS,不过每次需要入队的左右子节点是从参照列表中依次弹出字符串来构建的。
解题思路:
-
2. 序列化 使用 前序遍历DFS ,每次前序访问根节点时, 以 逗号 拼接,递归终止时, 空树 以 null 字符串拼接 ,
-
在 反序列化 时, 将 字符串按逗号分割 保存到一个 结果 队列list 中,然后在这个结果队列上执行DFS,每次递归中 从队列取 第一个字符串 构造出 根节点 , 然后递归调用 去构建当前根节点的 左右子树。 递归终止:当遇到 null 字符串时,递归函数返回 空树 即可。
114. 二叉树展开为链表
解题思路:
-
1. 前序遍历 ,先通过前序遍历将所有节点收集到结果集list中,然后再遍历list串联成链表即可。
解题思路:
-
2. 前序遍历 + 记住前一个节点 ,在递归过程中,访问 根节点 的时候串联,记住前一个节点 prev , 当 prev != null 时,将 prev 的 左指针置空 ,将 prev 的 右指针 指向 当前结点 。
这个代码需要注意的地方:要先记住左右孩子,因为 prev.right = node 操作会修改右孩子的指向,如果不先记住可能会形成死循环递归。参考下图理解:
比如这个时候,我们应该拿 1 的左子节点 2 和右子节点 5 去递归,但是当执行左子节点 2 的过程中,会把 1 的右指针指向修改为指向节点 2:
这样本应该拿 5 去递归的就会变成了拿 2 去递归了,就会出现问题,因此要在上一步中先记住那个 5,那后面即便修改了指向,也没有关系。
当然也可以使用迭代版本的前序遍历:
这个就不用先记住了,因为例如处理 1 的时候,两个子节点 2 和 5 会被压入到栈里面,下次从栈里面顺序弹出就可以得到它们。
解题思路:
-
3. 原地指针置换 (移花接木) , cur 从 根节点 开始,如果当前节点的 左子树 != null ,就循环找到 【 cur 左子树的最右】 ,
-
然后将 【 cur 的右子树】 摘下来挂到 找到的 【 cur 左子树的最右】 的 右指针 上面 ,接着再将 【 cur 的左子树】 摘下来 ,挂到 【 cur<