今天继续解答leetcode上的一个问题,关于二叉树遍历的。
题目
Given a binary tree, return the bottom-up level order traversal of its nodes’ values. (ie, from left to right, level by level from leaf to root).
For example:
Given binary tree {3,9,20,#,#,15,7},
3
/ \
9 20
/ \
15 7
return its bottom-up level order traversal as:
[
[15,7],
[9,20],
[3]
]
根据例子及题意分析,该题要求对于一个二叉树进行层序遍历,并将每一层的内容放到一个LIST中,最终把各层的LIST放到一个总的LIST里,并且是倒序放置。
分析
本题的考察点在于二叉树的层序遍历,一般的层序遍历的思路是,借用一个辅助的队列,主要思路如下:
- 将树的根节点放在队列里
- 如果队列不为空,则进入步骤3,否则进行步骤5
- 取出队头元素并打印,同时,将队头元素的左右子节点(如果有的话)再放入队尾
- 转到步骤2
- 结束
但以上逻辑有一个问题是虽然可以分层打印,但无法判断每一层的结束。所以在这里需要稍做改动,个人的想法是,不使用队列,而是使用一个节点LIST,以及一个值列表。思路如下:
- 将树的根节点放在节点列表里
- 如果节点列表不为空,则对其遍历,进入步骤3,否则到7
- 定义一个临时的节点列表L,并初始化值列表
- 遍历原节点列表,将每一个节点的值取出,放入值列表中。并将元素的左右子节点(如果有的话)再放入临时节点列表L里
- 将值列表存储到最终的结果列表里,将原节点列表指向临时节点列表
- 转到2
- 结束
以下是相关代码:
/**
* 本算法的大体思路如下:
* 1. 处理ROOT,并将ROOT的左右节点放到一个列表中去
* 2. ROOT处理完后,若列表不为空,则再循环处理那个列表,对于列表中的每个元素,将其子元素放到列表中去
* 3. 依次循环,直到列表为空
* @param root 树的头节点
* @return 最终结果
*/
public List<List<Integer>> levelOrderBottom(TreeNode root) {
if(root == null){
return Collections.emptyList();
}
List<List<Integer>> resultList = new ArrayList<List<Integer>>();
List<TreeNode> levelList = new ArrayList<TreeNode>();
List<Integer> valueList = null;
//初始化,把ROOT加进去
levelList.add(root);
while(!levelList.isEmpty()){
valueList = new ArrayList<Integer>();
List<TreeNode> nodeList = new ArrayList<TreeNode>();
// 每次循环实际上就是处理了一层
for(TreeNode treeNode : levelList){
valueList.add(treeNode.val);
// 为下一次循环做准备
if(treeNode.left != null){
nodeList.add(treeNode.left);
}
if(treeNode.right != null){
nodeList.add(treeNode.right);
}
}
// 处理完本层后,需要将结果进行存储,由于是倒序,所以需要加在头节点。
resultList.add(0, valueList);
levelList = nodeList;
}
return resultList;
}
代码通过leetcode的单元测试,性能上来看属于中间水平,本文中的并不一定是最优解,期待有更好的解法。