完全二叉樹節點個數
阿新 • • 發佈:2019-01-07
文章目錄
完全二叉樹節點個數
最簡單的解法就是遍歷這棵樹,時間複雜度是O(N),如果只是這一種解法,就不會有本文了。本文中給出兩種解法。
完全二叉樹
第一次看到完全二叉樹的定義比較懵,搜尋到的定義如下:
設二叉樹的深度為h,除第 h 層外,其它各層 (1~h-1) 的結點數都達到最大個數,第h層所有的結點都連續集中在最左邊,這就是完全二叉樹。
誰到不想看這個定義,比較簡單的理解就是和滿二叉樹相比較,看按層次遍歷的標號是否一致。具體方案不再闡述,網上都有。
實現
- 遍歷
- 藉助完全二叉樹的特點
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
遍歷
看一下遞迴的公式:
- 空樹:返回0
- 非空樹:遞迴的統計左右子樹的節點個數,返回左右子樹節點個數加1的和
func countNodes(root *TreeNode) int {
if root == nil {
return 0
}
sumL := countNodes(root.Left)
sumR := countNodes(root.Right)
return sumL+sumR+1
}
藉助完全二叉樹的特點
這個特點是什麼呢?完全二叉樹=滿二叉樹+完全二叉樹。完全二叉樹裡藏著一顆滿二叉樹和另外一顆完全二叉樹,最驚喜的是從公式裡看出子問題和原問題基本一致,可以使用遞迴啊。
完全二叉樹的層數
這種演算法的實現需要知道完全二叉樹的層數,難道又需要遍歷統計嗎,當然不需要了,還是藉助完全二叉樹的特點,可以根據完全二叉樹的最左節點和一個計數變數搞定,因為這個最左節點肯定是位於最後一層。
func height(root *TreeNode) int {
h := 0
for root != nil {
h++
root = root.Left
}
return h
}
原理
- h = height(root), hright = height(root.Right)
- 左子樹和右子樹其中有一顆是完全二叉樹,另一顆是滿二叉樹
- 區別左右子樹的種類根據h-hright
- h-hright=1:
- 左子樹:滿二叉樹
- 右子樹:完全二叉樹
- h-hright=2:
- 左子樹:完全二叉樹
- 右子樹:滿二叉樹
- h-hright=1:
- 節點個數=1+左子樹節點個數+右子樹節點個數 = (1 << hright)+遞迴另一顆完全二叉樹(滿二叉樹 = 1 << hright)
第一種情況
第二種情況
實現
func countNodes(root *TreeNode) int {
if root == nil {
return 0
}
return nodeNums(root)
}
func nodeNums(root *TreeNode) int {
h := height(root)
hR := height(root.Right)
//兩種情況滿二叉樹層數都是hR
//不同在於遞迴左子樹還是右子樹
nums := 1 << uint(hR)
if hR+1 == h {
return nums+countNodes(root.Right)
}
return nums+countNodes(root.Left)
}
func height(root *TreeNode) int {
h := 0
for root != nil {
h++
root = root.Left
}
return h
}
時間複雜度
對於每一個節點最多需要訪問深度個數的節點,所以最終時間複雜度是O(lg2*lg2)。
關於作者
大四學生一枚,分析資料結構,面試題,golang,C語言等知識。QQ交流群:521625004。微信公眾號:後臺技術棧。