二叉樹樹中和爲某一值的路徑,該題目是劍指offer上的一道題目,第一次刷題的時候一次就過了,所以沒有當回事,當我遇到一個該題目的變形題的時候卻一直通過不了,發現自己還是眼高手低,因此重新總結和記錄一下。
二叉樹中和爲某一值的路徑
題目描述
面試題34. 二叉樹中和爲某一值的路徑
輸入一棵二叉樹和一個整數,打印出二叉樹中節點值的和爲輸入整數的所有路徑。從樹的根節點開始往下一直到葉節點所經過的節點形成一條路徑。
示例:
給定如下二叉樹,以及目標和 sum = 22,
返回:
分析: 尋找二叉樹中和爲某一值的路徑,那麼就是從根節點出發找到它的葉子節點,二叉樹遍歷中只有先序遍歷是從根節點出發,因此我們使用先序遍歷來解決這道題。實現思路可以直接看代碼。
代碼實現
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<List<Integer>> pathSum(TreeNode root, int sum) {
List<List<Integer> > lists=new ArrayList<>();
//判非
if(root==null){
return lists;
}
List<Integer> list=new ArrayList<>();
countPathSum(root,sum,lists,list);
return lists;
}
public void countPathSum(TreeNode root,int sum,List<List<Integer> > lists,List<Integer> list){
//判斷遞歸終止條件
if(root==null){
return;
}
//當前要執行的操作
sum-=root.val;
list.add(root.val);
//如果該節點爲葉子節點並且sum爲0,則加入路徑
if(sum==0&&root.left==null&&root.right==null){
lists.add(new ArrayList(list));
}
//更深層次的遍歷
countPathSum(root.left,sum,lists,list);
countPathSum(root.right,sum,lists,list);
//重置
sum-=root.val;
list.remove(list.size()-1);
}
}
題目變形——獲得路徑的最高分
題目描述
這道題目明顯是二叉樹中和爲某一路徑的變形題,不同之處是這道題是N叉樹,最高分是乘積。使用遞歸解題方法與上面相似。這裏需要記錄一下的是自己一直通不過的原因:
自己原來的代碼是下面這樣的:
也就是把重置原來的狀態放到了for循環裏面了,傻乎乎的認爲for循環裏面每次執行完遞歸都要重置狀態,導致只能走到最左邊的一條路徑,其實對比上面的二叉樹中和爲某一值的路徑就可以得到答案,for循環中每次去遞歸都是用的當前狀態,因此需要在for循環外面重置狀態
for (int i = 0; i < edges.length; i++) {
if (edges[i][0] == rootNode && !visited[edges[i][1]]) {
helper(numsNode, edges[i][1], values, edges, visited, score);
//重新加載原來的屬性
score /= values[rootNode-1];
visited[rootNode]=false;
}
}
代碼實現
package zhongxing;
public class Test1 {
/*
*
給出了一顆有N個節點的樹,索引從1到N,樹的每個節點都有一個值。她想要追蹤從根到其中一個葉子的路徑。以便她能夠獲得該路徑的最高得分。
路徑的最高分定義爲該路徑中節點值的成績
輸入:
numNodes 表示樹中節點數的整數
rootNode 表示樹中根節點索引的整數
values一個整數列表,表示樹中各節點的值
edges,一個整數列表,其中列表的每個元素包含樹的一對邊
輸出 返回一個整數,表示可能的最大得分
解決思路:可以使用深度優先搜索 從根節點出發 進行深度優先搜索
*/
private static int maxScore;
public static int find(int numsNode, int rootNode, int[] values, int[][] edges) {
boolean visited[] = new boolean[numsNode + 1];
int res = 0;
res = helper(numsNode, rootNode, values, edges, visited, 1);
return res;
}
public static int helper(int numsNode, int rootNode, int[] values, int[][] edges, boolean[] visited,int score) {
visited[rootNode] = true;
score *= values[rootNode-1];
maxScore = maxScore > score ? maxScore : score;
for (int i = 0; i < edges.length; i++) {
if (edges[i][0] == rootNode && !visited[edges[i][1]]) {
helper(numsNode, edges[i][1], values, edges, visited, score);
}
}
//重新加載原來的屬性
score /= values[rootNode-1];
visited[rootNode]=false;
return maxScore;
}
public static void main(String[] args) {
int[] values = { 2, 4, 100, 30, 9 };
int[][] edges = { { 1, 2 }, { 1, 3 }, { 2, 4 }, { 2, 5 } };
int res = find(5, 1, values, edges);
System.out.println(res);
}
}
寫到最後
最後,回顧一下使用遞歸解決問題的套路:
第一步:判斷遞歸終止條件(如上面這道變形題,遞歸終止條件可能是在進一步遞歸的時候就確定了)
第二步:確定當前的操作
第三步:進行更深層次的遞歸
第四步:重置爲原來的狀態