打印二叉樹的邊界節點有兩個標準,這裏只看標準一:
1. 頭節點爲邊界節點
2. 葉節點爲邊界節點
3. 如果節點在其所在的層中是最左或最右的,那麼也是邊界節點
左程雲的《程序員代碼面試指南》裏面的解法如下:
1. 遞歸遍歷樹,找到樹的最大高度,然後定義保存每層最左最右邊界節點的二維數組
2. 遞歸找出每層最左最右邊界節點(如果該層只有一個節點,那麼會重複保存)
3. 先從上往下打印左邊界節點,然後遞歸找到每層的葉子節點並打印,最後從下往上打印最右邊界節點
代碼上遞歸用的比較多,而且要好幾次DFS遍歷樹,我給出的解法做了一點優化:
1. 使用一次BFS層遍歷樹,就可以找出所有需要的節點
2. 不用計算樹的高度,並且無遞歸代碼
算法代碼如下:
public void printEdgeNodes(TreeNode head){
Deque<TreeNode> q = new LinkedList<>();
List<TreeNode> lefts = new ArrayList<>(); // 保存最左邊界節點
Stack<TreeNode> rights = new Stack<>(); // 保存最右邊界節點,因爲是從下往上打印,所以用棧
List<TreeNode> leafs = new ArrayList<>(); // 保存每層的葉子節點
q.addLast(head); // 預先放入頭節點
while (!q.isEmpty()){
int size = q.size();
for (int i = 0; i < size; i++){
TreeNode cur = q.removeFirst();
// if - else 保證節點不會重複出現在不同集合裏
if (i == 0){
lefts.add(cur);
} else if (i == size - 1){
rights.push(cur);
} else if (cur.left == null && cur.right == null){
leafs.add(cur);
}
// 添加當前節點的左右節點到隊列
if (cur.left != null)
q.addLast(cur.left);
if (cur.right != null)
q.addLast(cur.right);
}
}
// 先打印左邊界
for (TreeNode cur : lefts){
System.out.println(cur.value);
}
// 再打印葉子節點
for (TreeNode cur : leafs){
System.out.println(cur.value);
}
// 最後打印有邊界
while (!rights.isEmpty()){
System.out.println(rights.pop().value);
}
}