给每个leaf(包括null)编号
A
/ \
B C
/ \ / \
D E F #
00 01 10 11
编号对应从root走到这个leaf的路径
e.g. 00 表示左->左, 01表示左->右
编号的二进制位数为树高(h), 最大id为2^h-1
e.g. 树高2 -> leafId in range [0 - 11], i.e. [0 - 2^2-1]
树高3 -> leafId in range [0 - 111], i.e. [0 - 2^3-1]
然后就对leaf进行二分查找,找到id最大的non-null-leaf(上图中的F)
二分查找(左闭右闭)停止时, hi对应的就是这个id (why?看以下链接)
https://blog.nowcoder.net/n/738406717b8b4ffbb9a5f619b2b554ac
总共节点数 = # non-leaf + # leaf
= 2^h-1 + (hi+1)
对应上面的例子 = 2^2-1 + (2+1) = 6
public class Solution {
public int nodeNum(TreeNode head) {
if (head == null) return 0;
TreeNode t = head;
int h = 0; // tree height (i.e. num levels - 1)
while (t.left != null) {
t = t.left;
h++;
}
if (h == 0) return 1; // single node tree
// assign leaf (including nulls) with ids 0 - 2^h-1
// binary search for the last non-null leaf
int lo = 0, hi = (int) Math.pow(2, h)-1;
while (lo <= hi) {
int mid = lo + ((hi-lo) >> 1);
if (isNullLeaf(mid, h, head)) {
hi = mid - 1;
} else {
lo = mid + 1;
}
}
int numNonLeaf = (int) Math.pow(2, h) - 1;
// hi is the id of last non-null leaf
// # leaf = hi + 1
return numNonLeaf + hi + 1;
}
// Traverse from root to leaf based on the leafId.
public boolean isNullLeaf(int leafId, int h, TreeNode head) {
int bitmask = 1 << h-1;
TreeNode cur = head;
while (bitmask > 0) {
boolean goRight = (bitmask & leafId) > 0;
if (goRight) cur = cur.right;
else cur = cur.left;
bitmask >>= 1;
}
return cur == null;
}
}