1,問題描述
輸入一顆二叉樹的跟節點和一個整數,打印出二叉樹中結點值的和爲輸入整數的所有路徑。路徑定義爲從樹的根結點開始往下一直到葉結點所經過的結點形成一條路徑。(注意: 在返回值的list中,數組長度大的數組靠前)
2,解題思路
(1)注意事項
- 滿足該題條件的路徑一定是從根節點到葉節點,也就是說,即使根節點到某個非葉子節點的節點值之和等於目標值,那該條路徑也不能算作本題定義的路徑。
- 如果你採用的是深度優先遍歷,那麼該題括號中的注意部分是可以忽略的。因爲輸入的是樹的層次遍歷序列,所以,左子樹的深度一定大於等於右子樹的深度,所以先深度優先遍歷左子樹再遍歷右子樹,所得到滿足條件的數組長度一定是從大到小。
- 深度優先遍歷要時刻注意節點回退的問題,節點回退的操作在源碼中有標註。
- 本題源碼中有幾處注意事項,源碼中已經標註。
(2)思路分析
從根節點開始遍歷,每遍歷一個節點,先將該節點添加進list中,再判斷一下是否已經滿足條件,若已經滿足,則將該數組添加進大的list中,並進行回退;否則,繼續遞歸遍歷該節點的左子樹以及右子樹,遍歷完一個子樹後要進行節點回退。
一種思路兩種實現方案,第一種方案進行了各種判斷,目的是減少遞歸的次數。第二種方案實現起來簡單粗暴,幾乎沒有任何判斷,但是遞歸的次數可能比第一種方案要多。
3,源碼
import java.util.ArrayList;
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
private ArrayList<ArrayList<Integer>> arrayList = new ArrayList<ArrayList<Integer>>();
private ArrayList<Integer> list = new ArrayList<Integer>();
public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
if(root==null) return arrayList;
//findPath(root,target);
findPath1(root,target);
return arrayList;
}
//方案一
public void findPath(TreeNode root, int target){
//如果root.val>target,說明沒有滿足的路徑
if(root==null || root.val>target) return;
target -= root.val;
list.add(root.val);
if(target>0) {
if(root.left!=null) findPath(root.left, target);
if(root.right!=null) findPath(root.right, target);
//遍歷到葉節點後要進行節點回退。
list.remove(list.size()-1);
}else if(target==0 && root.left==null && root.right==null) {
//new ArrayList<Integer>(list)是分配一個新的引用指向現有的list,
//目的是不改變現有的list,方便以後可以繼續操作該list
arrayList.add(new ArrayList<Integer>(list));
//找到滿足條件的路徑後要進行節點回退。
list.remove(list.size()-1);
}else {
//沒有找到滿足條件的路徑,也要進行節點回退。
list.remove(list.size()-1);
}
}
//方案二:
private void findPath1(TreeNode root, int target) {
if(root==null) return;
target -= root.val;
list.add(root.val);
if(target==0 && root.left==null && root.right==null) {
arrayList.add(new ArrayList<Integer>(list));
}
findPath1(root.left, target);
findPath1(root.right, target);
list.remove(list.size()-1);
}
}