这道题可以当成一般的二叉树直接遍历,但是我们如果利用完全二叉树的特点遍历,可以节省一些时间。不过时间复杂度两者其实都是O(n)。那么所谓的特点指的是什么呢?完全二叉树只有两种情况,要么是满二叉树,要么有一部分子树是满二叉树。我们可以统计子树的左右两侧节点,来判断该子树是否是满二叉树(注意仅限于这道题可以这样判断,因为在整棵树为完全二叉树的前提下,子树如果为满二叉树,那么它的左右两侧节点的高度一定相同)。这就导致了这道题与之前的题目最大的区别就是终止条件上。在写终止条件时,要计算以该父节点为根节点的子树的两侧节点高度,如果相同,则直接退出本层递归。这是本题大致思路,大家可以结合我下面的代码以及注释理解。
代码及注释如下:
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:int countNodes(TreeNode* root) {//终止条件1if(root == NULL) return 0;//终止条件2TreeNode* left = root -> left;TreeNode* right = root -> right;int leftDepth = 0,rightDepth = 0;while(left != NULL){left = left -> left;leftDepth++;}while(right != NULL){right = right -> right;rightDepth++;}if(leftDepth == rightDepth){return (1 << leftDepth + 1) - 1;//满二叉树可以直接用公式算}//递归左子树int leftTreeNum = countNodes(root -> left);//递归右子树int rightTreeNum = countNodes(root -> right);//处理逻辑:计算左右子树节点个数,返回给当前父节点int result = leftTreeNum + rightTreeNum + 1;return result;}
};