**
劍指offer 二叉樹中和爲某一值的路徑
**
題目描述
輸入一顆二叉樹的跟節點和一個整數,打印出二叉樹中結點值的和爲輸入整數的所有路徑。路徑定義爲從樹的根結點開始往下一直到葉結點所經過的結點形成一條路徑。(注意: 在返回值的list中,數組長度大的數組靠前)
提到樹,首先就應該想起用遞歸操作。
這道題的路徑要求是從root到leaf,根據題目,遞歸的終止條件就是node.left == null && node.right == null && node.val == target
public class Solution {
public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
ArrayList<ArrayList<Integer>> res = new ArrayList<>();
if(root == null) return res;
helper(root , target , new ArrayList<Integer>() , res);
return res;
}
public void helper(TreeNode node , int target , ArrayList<Integer> list , ArrayList<ArrayList<Integer>> res) {
list.add(node.val);
if(node.left == null && node.right == null && node.val == target) {
res.add(new ArrayList<>(list));
}
if(node.left != null) helper(node.left , target-node.val , list , res);
if(node.right != null) helper(node.right , target-node.val , list , res );
list.remove(list.size()-1);
}
}
Leetcode 112. Path Sum
Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum.
同類型題,只是沒有要求把結果返回,只是判斷,所以更加簡單
class Solution {
public boolean hasPathSum(TreeNode node, int target) {
if(node == null) return false;
if(node.left == null && node.right == null && node.val == target) return true;
return hasPathSum(node.left , target-node.val) || hasPathSum(node.right , target-node.val);
}
}
Leetcode 113.Path Sum II
與劍指offer是同一題
Leetcode 437. Path Sum III
You are given a binary tree in which each node contains an integer value.
Find the number of paths that sum to a given value.
The path does not need to start or end at the root or a leaf, but it must go downwards (traveling only from parent nodes to child nodes).
The tree has no more than 1,000 nodes and the values are in the range -1,000,000 to 1,000,000.
這道題對路徑的start和end沒有要求,也就是說路徑start和end不必是樹的root和leaf,所以,我們需要對樹的每一個節點都做判斷,以當前節點爲start的路徑,擁有多少條路徑和爲sum的路徑,所有這些路徑加起來,就是結果。
class Solution {
public int pathSum(TreeNode root, int sum) {
if(root == null) return 0;
int res = 0;
res += helper(root , sum);
res += pathSum(root.left , sum) + pathSum(root.right , sum);
return res;
}
//以node爲start,返回有多少條路徑和爲target
public int helper(TreeNode node , int target ) {
if(node == null) return 0;
int num = 0;
if(node.val == target) num += 1;
num += helper(node.left , target-node.val );
num += helper(node.right , target-node.val);
return num;
}
}
在discuss中找到的該題的另一個解決方案,比較難懂
discuss
class Solution {
public int pathSum(TreeNode root, int sum) {
HashMap<Integer, Integer> preSum = new HashMap();
preSum.put(0,1);
return helper(root, 0, sum, preSum);
}
public int helper(TreeNode root, int currSum, int target, HashMap<Integer, Integer> preSum) {
if (root == null) {
return 0;
}
currSum += root.val;
int res = preSum.getOrDefault(currSum - target, 0);
preSum.put(currSum, preSum.getOrDefault(currSum, 0) + 1);
res += helper(root.left, currSum, target, preSum) + helper(root.right, currSum, target, preSum);
preSum.put(currSum, preSum.get(currSum) - 1);
return res;
}
}
解釋:
因此,這個想法類似於兩個和,使用HASMAP來存儲(關鍵字:前綴和,值:有多少種方法得到這個前綴和),並且每當到達一個節點,我們檢查前綴和目標是否存在於HASMAP中,如果有,我們將前綴和目標的方式添加到REST中。
例如:在一個路徑中,我們有1,2,-1,-1,2,那麼前綴和將是:1,3,2,1,3,假設我們要找到的目標和是2,那麼我們將有{2},{1,2,-1},{2,-1,-1,2}和{2}方法。
1、前綴存儲遞歸中從根到當前節點的和
2、在到達當前節點之前,映射存儲<prefix sum,frequency>對。我們可以想象從根到當前節點的路徑。從路徑中間到當前節點的任何節點的總和=從根到當前節點的總和和中間節點的前綴和之間的差值。
3、我們正在尋找一些連續的節點,這些節點的總和爲給定的目標值,這意味着在2中討論的差異。應該等於目標值。此外,我們需要知道有多少差異等於目標值。
4、地圖來了。映射存儲當前節點路徑中所有可能和的頻率。如果在地圖中存在當前和和目標值之間的差異,則在路徑的中間必須存在一個節點,使得從該節點到當前節點,總和等於目標值。
5、注意,中間可能有多個節點滿足4中討論的內容。地圖上的頻率是用來幫助解決這個問題的。
6、因此,在每次遞歸中,映射都會存儲我們計算到目標的範圍總數所需的所有信息。請注意,每個範圍從中間節點開始,由當前節點結束。
7、爲了得到路徑總數,我們將樹中每個節點結束的有效路徑數相加。
8、每個遞歸返回以當前節點爲root的子樹中有效路徑的總數。這個總數可以分爲三部分:
-子樹中以當前節點的左子節點爲root的有效路徑總數
-子樹中以當前節點的右子節點爲root的有效路徑總數
-以當前節點爲end的有效路徑數