劍指 Offer 34. 二元樹中和為某一值的路徑(java解題)

2023-02-19 12:00:27

1. 題目

給你二元樹的根節點 root 和一個整數目標和 targetSum ,找出所有 從根節點到葉子節點 路徑總和等於給定目標和的路徑。

葉子節點 是指沒有子節點的節點。

範例 1:

輸入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
輸出:[[5,4,11,2],[5,8,4,5]]

範例 2:

輸入:root = [1,2,3], targetSum = 5
輸出:[]

範例 3:
輸入:root = [1,2], targetSum = 0
輸出:[]

提示:

樹中節點總數在範圍 [0, 5000] 內
-1000 <= Node.val <= 1000
-1000 <= targetSum <= 1000

作者:Krahets
連結:https://leetcode.cn/leetbook/read/illustration-of-algorithm/5dy6pt/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。

2. 解題思路

首先能夠想到的是用二元樹遞迴的方式來查詢路徑,每次遞迴都需要修改target的值,在這種做法中有一個問題:如何設定返回值,從而返回路徑列表,且在程式中如何修改路徑列表?

在官方題解中,在類的定義中適用resultpath兩個公共變數,可以讓不同的函數均基於這塊公共區域加以修改。

遍歷使用的是先序遍歷。

  • 如果需要繼續遍歷,將當前結點放入path路徑中;
  • 如果已經遍歷到葉子結點,且路徑之和等於target的值,將當前的路徑整體放入結果列表中;
  • 當某一層遍歷結束之後,需要將當前結點彈出路徑列表中,實現二叉遍歷

需要注意的是,由於list.add()使用的是淺拷貝,如果每次將path新增到結果列表中使用的是result.add(path),這樣寫忽略了list.add()是進行淺拷貝的,即每個路徑結果path都指向同一個記憶體地址,後續在此記憶體地址上的操作將會改變前期的結果。最終出現[[x,y,z][x,y,z][x,y,z]]三個子列表相同的情況。因此,每次寫入result列表應該新建一個path物件。

3. 資料型別功能函數總結

//LinkedList
LinkedList<E> listname=new LinkedList<E>();//初始化
LinkedList<E> listname=new LinkedList<E>(oldlist);//將oldlist的元素複製一份給listname,且是深拷貝
LinkedList.add(elment);//在連結串列尾部新增元素
LinkedList.removeFirst();//取出連結串列頭部元素

4. java程式碼

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
 // 考慮迭代,左右子樹再找某個目標值的路徑。
class Solution {
    LinkedList<List<Integer>> result=new LinkedList<List<Integer>>();
    LinkedList<Integer> path=new LinkedList<Integer>();
    public List<List<Integer>> pathSum(TreeNode root, int target) {
        recur(root,target);
        return result;
    }
    void recur(TreeNode root, int target) {
        if(root!=null){
            path.add(root.val);
            target-=root.val;
            if(target==0&&root.left==null&&root.right==null){//遍歷到葉節點且目標值正好等於路徑之和
                LinkedList<Integer> path_temp=new LinkedList<Integer>(path);
                result.add(path_temp);
            }
            recur(root.left,target);
            recur(root.right,target);
            path.removeLast();//回退時將當前元素出棧
        }
    }
}