2021-01-25 LeetCode 1530 好葉子節點個數
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
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;
}
}