1. 程式人生 > 其它 >2021-01-25 LeetCode 1530 好葉子節點個數

2021-01-25 LeetCode 1530 好葉子節點個數

技術標籤:二叉樹leetcode

cx天王蓋地虎

LeetCode 1530 二叉樹中好葉子節點個數

1.題目描述:

給你二叉樹的根節點root 和一個整數 distance
如果二叉樹中兩個 葉 節點之間的 最短路徑長度 小於或者等於 distance ,那它們就可以構成一組 好葉子節點對 。
返回樹中 好葉子節點對的數量

2.思路:

二叉樹有一條性質:任意兩個不同的葉子結點之間有且僅有一條最短路徑
對於兩個不同的葉子結點A,B,如果它倆的最近的公共祖先為P,則它倆的最短路徑等於A到P的距離加上B到P的距離。

基於上面的性質,我們只需遍歷所有非葉子結點P,得到以P為最近公共祖先的葉子結點對,統計出其中距離小於 distance的葉子結點對就可以得到答案。

對於任意一個節點,其
good pairs數量的數量=左子樹中good pairs數量 + 右子樹中good pairs數量 + 左右子樹以它為橋樑的good pairs數量

如何計算以它為橋樑的good pairs數量呢?這就需要獲知左子樹中所有與它距離不超過 distance-1的各種距離的葉子結點的數量(也就是需要知道與它距離為1的葉子結點有多少個?與它距離為2的葉子結點又有多少個?與它距離為……只需要記住距它為1到distance-1的各種節點的數量)

同樣也需要左子樹的這些資訊。

遍歷完任意一個結點,需要返回與它距離不同的葉子結點的數量,以及以它為樹根的樹中已經存在的good pairs數量。

是不是有遞迴的思路了(猥瑣的笑容.jpg
由於距離不大於 distance,用一個數組大小為distance的陣列depth[]儲存每種距離的葉子結點的數量

例如,對於一個葉子結點,由於它自己本身是葉子節點,因此對於它這棵樹而言,只有一個葉子節點且與它的距離為0,因此depth[0] == 1

又例如,對於下面這棵樹,如果distance給定3:
在這裡插入圖片描述
樹根P左子樹中有一個葉子結點,右子樹中也有一個葉子結點,並且與它的距離為1,那麼它返回的depth陣列應該為depth[1] == 2

,左(右)子樹中沒有已經存在的good pairs,但是AB以它為橋樑就構成一對good pairs:1+1<3

3.遞迴函式虛擬碼

class NodeMes{
  int goodpairs;//好葉子節點個數
  int[] depth;//不同距離的葉子結點的數量
}
//遞迴
dfs(root){
	if(當前結點為葉子結點){
		goodpairs = 0
		depth[0]=1
		return NodeMes
	}
	else//不為葉子結點
	leftMes=dfs(root.left);//遞迴獲得左子樹的資訊
	rightMes=dfs(root.right);//遞迴獲得右子樹的資訊
	結合左右子樹的資訊,更新goodpairs和depth
	return NodeMes	
}

4.程式碼實現

class NodeMes {
	int[] depth;
	int pairs;
	NodeMes(int pairs,int[] depth){
		this.pairs = pairs;
		this.depth = depth;
	}
}
class Solution {
    int distance;
	//題目的函式簽名
	public int countPairs(TreeNode root, int distance) {
		this.distance = distance;
		NodeMes retMes = getPairs(root);
        return retMes.pairs;
    }
	
	//對每一個結點,返回以當前結點為樹根的樹上所有不同深度的葉子結點的個數,以及好葉子結點的對數
	public NodeMes getPairs(TreeNode root) {
		int[] depth = new int[distance];
		if(root == null) {//為了避免後面對左右節點是否為空進行討論,減少程式碼量
			return new NodeMes(0,depth);
		}
		if(root.left == null && root.right == null) {
			//葉子結點
			depth[0] = 1;
			return new NodeMes(0,depth);
		}
		NodeMes leftMes = null, rightMes = null;
		leftMes = getPairs(root.left);//遞迴獲得左子樹的資訊
		rightMes = getPairs(root.right);//遞迴獲得右子樹的資訊		
		//根據左右子樹的資訊計算當前樹中goodpair數量
		int cnt = count(leftMes.depth, rightMes.depth) + leftMes.pairs + rightMes.pairs;
		//更新當前樹中葉子結點的數量以及距離:
		int[] nums = new int[distance];
		for(int i = distance - 1; i > 0; i--) {	//左右子樹同一距離的葉子結點數相加
			nums[i-1] = leftMes.depth[i-1] + rightMes.depth[i-1];
			nums[i] = nums[i-1];			 //同時距離(深度)+1
		}
		nums[0] = 0;						//邊界處理
		return new NodeMes(cnt, nums);
	}
	//根據左右子樹中不同距離的葉子結點的數量,計算出有多少對滿足 距離<=distance
	public int count(int[] n1, int[] n2) {
		int ret = 0;
		for(int i = 0; i < distance -1; i++) {
			for(int j = 0; j + i + 1 < distance; j++) {
				ret += n1[i] * n2[j];
			}
		}
		return ret;
	}
}