算法题-------关于单调栈的应用

在关于一行有高度的数字中,比如需要统计能看到的数字等等时,利用这种单调栈的数据结构就可以很好的解决问题;

比如现在有一行数据是2   6   5  4   3   7   1,且这是每个人的身高,每个人向右看,那么就统计每个人能看到的头顶的数量;

解法一就是,在每一个人处开始,向右遍历,比较身高,那么这个时间复杂度就为O(n^2);

如果利用单调栈,那么就可以实现O(n)的时间复杂度;此时使用的是递减栈。

使得入栈元素的顺序是从大到小;栈中元素的个数就是比自己身高小的人,使栈从左向右开始遍历;


vector FieldSum(vector& v)
{
	v.push_back(INT_MAX); // 这里可以理解为需要一个无限高的人挡住栈中的人,不然栈中元素最后无法完全出栈
	stack st;
	vector res(v.size()-1);
	int sum = 0;
	for (int i = 0; i < (int)v.size(); i++)
	{
		if (st.empty() || v[st.top()] > v[i]) // 小于栈顶元素入栈
		{
			st.push(i);
		}
		else
		{
			while (!st.empty() && v[st.top()] <= v[i])
			{
				int top = st.top(); // 取出栈顶元素
				st.pop();
				//这里举个例子,就知道下面这么做的意思了
				//首先看入栈的元素是[4,3
				//那么遇到7,就会看不见了,那么对于3来说就是,3与7之间没有人,从而i-top-1就等于0;
				//而7与4之间有3,那么i-top-1就等于1; 
				res[top] = (i - top - 1); // 这里需要多减一个1
			}
			st.push(i);
		}
	}
	
	return res;
}

下面一个例子:

给出一行数字,看成是一排楼房,一个人站在每个楼处,分别向前和向后看,那么只能看到比自己高的楼,然后将站在每栋楼处所看到楼的数目统计出来;

例子:

5   3    8   3   2    5

最笨的办法是,依次在每一栋楼处,遍历整个数组,进行比较;

这样时间复杂度就为O(n^2)

但是使用单调栈,向右看,就使用一个栈,栈里面的元素是从大到小,当栈顶元素比当前元素小,就push进去,每次到达一个楼房处就是能看到的楼的数量;当遇到比栈顶大的,就删除栈顶,依次比较;

int function_B()
{
	int n;
	cin >> n;
	vector vec(n);
	for (int i = 0; i < n; ++i)
	{
		cin >> vec[i];
	}

	vector left(n);
	stack sta;
	for (int i = 0; i < n; ++i)
	{
		//此时里面是剩下的能看见的从大到小的单调栈,当过大的时候,那么就剔除栈顶,再比较
		//这样还剩几个,就知道当前能看到几个
		left[i] = sta.size();	
		while (!sta.empty() && sta.top() <= vec[i])
		{
			sta.pop();
		}
		sta.push(vec[i]);
	}

	while (!sta.empty())
	{
		sta.pop();
	}

	vector right(n);
	for (int i = n - 1; 0 <= i; --i)
	{
		right[i] = sta.size();
		while (!sta.empty() && sta.top() <= vec[i])
		{
			sta.pop();
		}
		sta.push(vec[i]);
	}

	for (int i = 0; i < n; ++i)
	{
		cout << left[i] + 1 + right[i] << " ";
	}
	return 0;
}

 

你可能感兴趣的:(记录知识)