leecode 解题总结:222. Count Complete Tree Nodes

本文介绍了一种高效计算完全二叉树节点数量的方法,通过比较左右子树的高度判断是否为满二叉树,并据此快速得出节点总数,避免了传统层序遍历或递归方法的时间复杂度过高的问题。
#include <iostream>
#include <stdio.h>
#include <vector>
#include <string>
#include <queue>
using namespace std;
/*
问题:
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.

分析:完全二叉树,最后一层节点靠左摆放,可能最后一层没有填满。
数出完全二叉树的节点个数。最简单的方式:层序遍历,时间复杂度为O(n)
另一种是递归:以当前节点为根的节点个数=左子树节点个数 + 1 + 右子树个数
当遇到空结点,返回0;

输入:
15
1 2 3 4 5 6 7 8 9 N N N N N N
输出:
9

关键:
1 递归求点的个数超时;层序遍历超时。应该有常数时间可以计算出。
要是能数出所有叶节点的个数,即可,最后一层节点个数:
层序不行,层序必须是顺序遍历的。
2 解法2 :https://leetcode.com/problems/count-complete-tree-nodes/?tab=Solutions
如果每次走向最左边的结点和走向最右边的结点,两者高度相同,说明是满二叉树:
返回: (1 << height) - 1
否则说明是完全额二叉树,计算以当前节点左右子树高度+1
*/

 struct TreeNode {
     int val;
     TreeNode *left;
     TreeNode *right;
     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 };

class Solution {
public:
	int countNodesRecursion(TreeNode* root) 
	{
		if(!root)
		{
			return 0;
		}
		//先尝试直接获取高度,利用高度来计算
		TreeNode* left = root;
		TreeNode* right = root;
		int height = 0;
		while(right)
		{
			left = left->left;
			right = right->right;
			height++;
		}
		//说明是完全二叉树,返回节点
		if(NULL == left)
		{
			return ( (1 << height) - 1 );
		}
		int leftCount = countNodesRecursion(root->left);
		int rightCount = countNodesRecursion(root->right);
		return (leftCount + 1 + rightCount);
	}

	//层序遍历
	int levelOrder(TreeNode* root) {
		if(NULL == root)
		{
			return 0;
		}
		queue<TreeNode*> nodes;
		nodes.push(root);
		int size = 1;
		int nextSize = 0;
		int result = 0;
		TreeNode* node = NULL;
		while(!nodes.empty())
		{
			node = nodes.front();
			nodes.pop();
			result++;
			if(node->left)
			{
				nodes.push(node->left);
				nextSize += 1;
			}
			if(node->right)
			{
				nodes.push(node->right);
				nextSize += 1;
			}
			size--;
			if(0 == size)
			{
				size = nextSize;
				nextSize = 0;
			}
		}
		return result;
	}

    int countNodes(TreeNode* root) {
		int result = countNodesRecursion(root);
		//int result = levelOrder(root);
		return result;
    }
};

//构建二叉树,这里默认首个元素为二叉树根节点,然后接下来按照作为每个结点的左右孩子的顺序遍历
//这里的输入是每个结点值为字符串,如果字符串的值为NULL表示当前结点为空
TreeNode* buildBinaryTree(vector<string>& nums)
{
	if(nums.empty())
	{
		return NULL;
	}
	int size = nums.size();
	int j = 0;
	//结点i的孩子结点是2i,2i+1
	vector<TreeNode*> nodes;
	int value;
	for(int i = 0 ; i < size ; i++)
	{
		//如果当前结点为空结点,自然其没有左右孩子结点
		if("N" == nums.at(i))
		{
			nodes.push_back(NULL);
			continue;
		}
		value = atoi(nums.at(i).c_str());
		TreeNode* node = new TreeNode(value);
		nodes.push_back(node);
	}
	//设定孩子结点指向,各个结点都设置好了,如果但钱为空结点,就不进行指向
	for(int i = 1 ; i <= size ; i++)
	{
		if(NULL == nodes.at(i-1))
		{
			continue;
		}
		if(2 * i <= size)
		{
			nodes.at(i-1)->left = nodes.at(2*i - 1);
		}
		if(2*i + 1 <= size)
		{
			nodes.at(i-1)->right = nodes.at(2*i);
		}
	}
	//设定完了之后,返回根节点
	return nodes.at(0);
}

void deleteBinaryTree(TreeNode* root)
{
	if(!root)
	{
		return;
	}
	if(NULL == root->left && NULL == root->right)
	{
		delete root;
		root = NULL;
	}
	if(root)
	{
		deleteBinaryTree(root->left);
		deleteBinaryTree(root->right);
	}
}


void process()
{
	 vector<string> nums;
	 string value;
	 int num;
	 Solution solution;
	 vector<vector<string> > result;
	 while(cin >> num )
	 {
		 nums.clear();
		 for(int i = 0 ; i < num ; i++)
		 {
			 cin >> value;
			 nums.push_back(value);
		 }
		 TreeNode* root = buildBinaryTree(nums);
		 int nodeNum = solution.countNodes(root);
		 cout << nodeNum << endl;
		 deleteBinaryTree(root);
	 }
}


int main(int argc , char* argv[])
{
	process();
	getchar();
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值