【难】【二叉树】构造数组的MaxTree

题目:脑客爱刷题

二叉树定义如下:

class treenode
{
public:
	int data;
	shared_ptr<treenode> left,right;
	treenode(int d,const shared_ptr<treenode> &l,const shared_ptr<treenode> &r):data(d),left(l),right(r){}
	treenode() :data(0), left(nullptr), right(nullptr){}  
	treenode(int d) :data(d), left(nullptr), right(nullptr){}  
};

一个数组的MaxTree定义如下:
1,数组必须没有重复元素;
2,MaxTree是一棵二叉树,数组的每一个值对应一个二叉树节点;
3,包括MaxTree树在内并且在其中的每一颗子树上,值最大的节点都是树的头;

给定一个没有重复元素的数组arr,写出生成这个数组的MaxTree的函数,要求如果数组长度为N,时间复杂度O(N),额外空间复杂度O(N)。

struct hash_treenode
{
	int operator()(const shared_ptr<treenode> &a)const
	{
		return hash<int>()(a->data);
	}
};

//第三个参数isleft为真时,指本次弹出是为了得到左边的父节点,否则为右边的父节点
void pop_stack_and_add_parent(stack<shared_ptr<treenode>> &s,unordered_map<shared_ptr<treenode>,pair<shared_ptr<treenode>,shared_ptr<treenode>>,hash_treenode> &parent,const bool isleft)
{
	shared_ptr<treenode> tmp=s.top();
	s.pop();
	if(isleft && !s.empty())
		parent[tmp].first=s.top();
	if(!isleft && !s.empty())
		parent[tmp].second=s.top();
}

shared_ptr<treenode> MaxTree(const int* num,const int length)
{
	if(num==nullptr || length<=0)
		return nullptr;
	vector<shared_ptr<treenode>> nodes(length);
	//parent中的pair的first参数是左边第一个比节点大的数,pair的second参数是右边第一个比节点大的数
	unordered_map<shared_ptr<treenode>,pair<shared_ptr<treenode>,shared_ptr<treenode>>,hash_treenode> parent;
	pair<shared_ptr<treenode>,shared_ptr<treenode>> temp;
	temp.first=nullptr;
	temp.second=nullptr;
	//初始化nodes数组和parent容器
	for(int i=0;i<length;i++)
	{
		nodes[i]=shared_ptr<treenode>(new treenode(num[i]));
		parent[nodes[i]]=temp;
	}
	stack<shared_ptr<treenode>> s;
	for(int i=0;i<length;i++)
	{
		if(s.empty() || s.top()->data > nodes[i]->data)
		{
			s.push(nodes[i]);
		}
		else
		{
			while(!s.empty() && s.top()->data < nodes[i]->data)
				pop_stack_and_add_parent(s,parent,true);
			s.push(nodes[i]);
		}
	}
	//一个节点只有被s弹出,才能得到其左右父节点,所以最后要把栈s的元素弹出清空
	while(!s.empty())
		pop_stack_and_add_parent(s,parent,true);

	for(int i=length-1;i>=0;i--)
	{
		if(s.empty() || s.top()->data > nodes[i]->data)
		{
			s.push(nodes[i]);
		}
		else
		{
			while(!s.empty() && s.top()->data < nodes[i]->data)
				pop_stack_and_add_parent(s,parent,false);
			s.push(nodes[i]);
		}
	}
	while(!s.empty())
		pop_stack_and_add_parent(s,parent,false);

	shared_ptr<treenode> head=nullptr;
	for(int i=0;i<length;i++)
	{
		if(parent[nodes[i]].first==nullptr && parent[nodes[i]].second==nullptr)
		{
			head=nodes[i];
			continue;
		}
		shared_ptr<treenode> par;
		if(parent[nodes[i]].first==nullptr)
		{
			par=parent[nodes[i]].second;
		}
		else if(parent[nodes[i]].second==nullptr)
		{
			par=parent[nodes[i]].first;
		}
		else
		{
			shared_ptr<treenode> par1=parent[nodes[i]].first;
			shared_ptr<treenode> par2=parent[nodes[i]].second;
			par=par1->data > par2->data?par2:par1;
		}

		if(par->left==nullptr)
			par->left=nodes[i];
		else
			par->right=nodes[i];
	}
	return head;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值