問題描述:
輸入一顆二叉樹的跟節點和一個整數,打印出二叉樹中結點值的和爲輸入整數的所有路徑。路徑定義爲從樹的根結點開始往下一直到葉結點所經過的結點形成一條路徑。(注意: 在返回值的list中,數組長度大的數組靠前)
基本思路:
二叉樹的路徑問題,基於二叉樹的遍歷。也就是說既可以是遞歸形式也可以是非遞歸形式。
- 遞歸解決方案
- 以下是非遞歸方案:
以下三點是主要考慮的問題。
- 因爲要計算路徑上數的和,使用先序遍歷明顯是最佳方案。
- 在遍歷過程中需要記錄路徑,這裏引入一個List 用來記錄路徑
使用LinkedList
更合適,原題使用的是ArrayList
,所以這裏採用ArrayList
- 常規先序遍歷是把節點的右節點壓入棧,這裏是把含有右子樹的節點壓入棧。
目的是爲了方便回溯。回溯條件是棧頂節點 == 路徑隊列尾節點
代碼的骨架是先序非遞歸遍歷。只是在回溯的時候需要稍加註意
import java.util.*;
public class Solution {
public ArrayList<ArrayList<Integer>> FindPath(TreeNode root, int target) {
ArrayList<ArrayList<Integer>> ans = new ArrayList<>(); // 所有合格路徑集合
Stack<TreeNode> nStack = new Stack<>(); // 用於回溯的棧
ArrayList<TreeNode> paths = new ArrayList<>(); // 用於記錄路徑的隊列
TreeNode index = root; //當前節點
int current = 0; // 當前路徑的和
while (index != null || nStack.size() != 0) {
current = current + index.val; // 計算路徑和
paths.add(index); // 更新路徑
// 如果該節點合格,添加到路徑集合中
if (index.right == null && index.left == null && current == target) {
ArrayList<Integer> list = new ArrayList<>();
for (TreeNode t : paths) {
list.add(t.val);
}
ans.add(list);
}
if (index.right != null)
nStack.push(index); // 注意這裏區別於傳統的先序遍歷
// 訪問左子樹
if (index.left != null) {
index = index.left;
} else if (!nStack.isEmpty()) {
index = nStack.pop();
// 核心:路徑回溯
while (paths.get(paths.size() - 1) != index) {
current -= paths.get(paths.size() - 1).val;
paths.remove(paths.size() - 1);
}
index = index.right;
} else {
index = null;
}
}
return ans;
}
}