记录这道题的目的主要是想复习一下计算时间复杂度的方法。题目描述是这样的:
Given a complete binary tree, count the number of nodes.
Definition of a complete binary tree from Wikipedia:
In a complete binary tree every level, except possibly the last, is completely filled, and all nodes in the last level are as far left as possible. It can have between 1 and 2h nodes inclusive at the last level h.
计算一个完全二叉树(不是满二叉树)的所有结点数。
这里,我首先想到的是一个求解二叉树结点数的通法,也就是如下的代码:
int count(TreeNode* root)
{
if(root==NULL) return 0; //Nothing to count
return 1+count(root->left())+count(root->right());
}
这个算法可通用的所有二叉树,时间复杂度为:
在这道题中明显会超时,原因是我们并没有用上完全二叉树的特性,上面题目描述的完全二叉树的特性如下:
1.除最后一层叶子结点以外,所有层的结点数都是满的。2.最后一层叶子结点的结点尽可能的靠近左边,即把左边占满。
那么根据这个特性,可以知道,对于一个结点来说,只要它满足左子树的深度等于右子树的深度。那么,就知道该树的结点数为:
根据这个特性,我们就可以节省不少计算,思路就是:一直递归到左深等于右深,可以得到该子树的结点数,然后相加,代码如下:
class Solution {
public:
int countNodes(TreeNode* root) {
if(root==NULL) return 0;
TreeNode* l=root; TreeNode* r=root;
int lh=0;int rh=0;
while(l) {lh++;l=l->left;}
while(r) {rh++;r=r->right;}
if(lh==rh) return pow(2,lh)-1;
return 1+countNodes(root->left)+countNodes(root->right);
}
};
有意思的是这个算法的复杂度的计算。很明显的是,看最后的递归式:
1+countNodes(root->left)+countNodes(root->right)
可以看出是用分治的策略每次递归的时候对左子树和右子树进行操作,递归的深度明显就为logn.
而每次递归操作分别就是深度变化也就是
最终结果的式子就为:
关于,O(logn*logn)大还是O(n),这是一个高中问题,这边我图方便直接用matlab画了个函数图比较: