手撕算法——二叉樹中和爲某一值的路徑及變形

二叉樹樹中和爲某一值的路徑,該題目是劍指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);
	}

}

寫到最後

最後,回顧一下使用遞歸解決問題的套路:
第一步:判斷遞歸終止條件(如上面這道變形題,遞歸終止條件可能是在進一步遞歸的時候就確定了)
第二步:確定當前的操作
第三步:進行更深層次的遞歸
第四步:重置爲原來的狀態

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章