給出一個完全二叉樹,求出該樹的節點個數。
說明:
完全二叉樹的定義如下:在完全二叉樹中,除了最底層節點可能沒填滿外,其餘每層節點數都達到最大值,並且最下面一層的節點都集中在該層最左邊的若干位置。若最底層爲第 h 層,則該層包含 1~ 2h 個節點。
示例:
輸入:
1
/ \
2 3
/ \ /
4 5 6
輸出: 6
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int countNodes(TreeNode root) {
if(root == null) return 0;
}
int left = countLevel(root.left);
int right = countLevel(root.right);
if(left = right){
return countNodes(root.right) + (1<<root.left);
}else{
return countNodes(root.left)+(1<<root.right)
}
private int countLevel(TreeNode root){
int level = 0;
while(root != null){
root = root.left;
k++;
}
return level;
}
方法一:線性時間
算法:
最簡單的解決方法就是用遞歸一個一個的計算節點。
class Solution {
public int countNodes(TreeNode root) {
return root != null ? 1 + countNodes(root.right) + countNodes(root.left) : 0;
}
}
複雜度分析
時間複雜度:\mathcal{O}(N)O(N)。
空間複雜度:\mathcal{O}(d) = \mathcal{O}(\log N)O(d)=O(logN),其中 dd 指的是樹的的高度,運行過程中堆棧所使用的空間。
方法二:二分搜索
方法一沒有利用完全二叉樹的特性。完全二叉樹中,除了最後一層外,其餘每層節點都是滿的,並且最後一層的節點全部靠向左邊。
這說明如果第 k 層不是最後一層,則在第 k 層中將有 2^k 個節點。由於最有一層可能沒有完全填充,則節點數在 1 到 2^d 之間,其中 d 指的是樹的高度。
我們可以直接計算除了最後一層以外的所有結點個數:
現在有兩個問題:
最後一層我們需要檢查多少個節點?
一次檢查的最佳的時間性能是什麼?
讓我們從第一個問題開始思考。最後一層的葉子節點全部靠向左邊,我們可以用二分搜索只檢查葉子代替檢查全部葉子。
讓我們思考第二個問題,最後一層的葉子節點索引在 0 到 $2^d - 1$ 之間。如何檢查第 idx 節點是否存在?讓我們來用二分搜索來構造從根節點到 idx 的移動序列。如,idx = 4。idx 位於 0,1,2,3,4,5,6,7 的後半部分,因此第一步是向右移動;然後 idx 位於 4,5,6,7 的前半部分,因此第二部是向左移動;idx 位於 4,5 的前半部分,因此下一步是向左移動。一次檢查的時間複雜度爲 {O}(d)O(d)。
我們需要{O}(d)O(d) 次檢查,一次檢查需要{O}(d)O(d),所以總的時間複雜度爲{O}(d^2)O(d`2 )。
算法:
class Solution:
def compute_depth(self, node: TreeNode) -> int:
"""
Return tree depth in O(d) time.
"""
d = 0
while node.left:
node = node.left
d += 1
return d
def exists(self, idx: int, d: int, node: TreeNode) -> bool:
"""
Last level nodes are enumerated from 0 to 2**d - 1 (left -> right).
Return True if last level node idx exists.
Binary search with O(d) complexity.
"""
left, right = 0, 2**d - 1
for _ in range(d):
pivot = left + (right - left) // 2
if idx <= pivot:
node = node.left
right = pivot
else:
node = node.right
left = pivot + 1
return node is not None
def countNodes(self, root: TreeNode) -> int:
# if the tree is empty
if not root:
return 0
d = self.compute_depth(root)
# if the tree contains 1 node
if d == 0:
return 1
# Last level nodes are enumerated from 0 to 2**d - 1 (left -> right).
# Perform binary search to check how many nodes exist.
left, right = 1, 2**d - 1
while left <= right:
pivot = left + (right - left) // 2
if self.exists(pivot, d, root):
left = pivot + 1
else:
right = pivot - 1
# The tree contains 2**d - 1 nodes on the first (d - 1) levels
# and left nodes on the last level.
return (2**d - 1) + left
作者:LeetCode
鏈接:https://leetcode-cn.com/problems/count-complete-tree-nodes/solution/wan-quan-er-cha-shu-de-jie-dian-ge-shu-by-leetcode/
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/count-complete-tree-nodes
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。