左神算法学习日记——单调栈

单调栈,一种可以找到左右边界的数据结构 

//利用单调栈找到一个数的左边最近的比他小的数(左边界)和右边最近的比他小的数(右边界)
int maxhist(vector<int> hist)
{
	stack<int> max;
	int res = INT_MIN;
	for (int i = 0; i < hist.size(); i++)
	{
		//栈从小到大排列,当当前数比栈顶数小时,则弹出栈顶数,结算当前结点,当前数就是他的右边界,弹出后的栈顶数就是他的左边界
		while (!max.empty() && hist[max.top()] >= hist[i])
		{
			int h = hist[max.top()];
			max.pop();
			int l = max.size() == 0 ? -1 : max.top();
			res = std::max(res, (i - l - 1)*h);
		}
		max.push(i);
	}
	//在将数组中所有的数都建立单调栈后,如果数组中还有元素的话说明栈中数的右边界是整个数组的右边界
	while (!max.empty())
	{
		int h = hist[max.top()];
		max.pop();
		int l = max.size() == 0 ? -1 : max.top();
		res = std::max(res, (int)(hist.size() - l - 1)*h);
	}
	return res;
}

int maxmat(vector<vector<int>> mat)
{
	vector<int> hist = mat[0];
	int res = maxhist(hist);
	//求矩阵中的最大矩阵面积,按行遍历矩阵,转化为矩阵高的数组,利用单调栈求矩阵的面积
	for (int i = 1; i < mat.size(); i++)
	{
		for (int j = 0; j < hist.size(); j++)
			hist[j] = mat[i][j] == 0 ? 0 : hist[j] + 1;
		res = std::max(res, maxhist(hist));
	}
	return res;
}
//当环形山峰中有重复元素时,求出其组合数就是相邻且高度相同的可以互相看到的山峰个数
int getteam(int time)
{
	return time>1 ? time*(time - 1) / 2 : 0;
}
//一个环形山峰,找出能互相看见彼此的山峰对数
int getneigh(vector<int> arr)
{
	int maxindex;
	for (int i = 0; i < arr.size(); i++)
	{
		maxindex = arr[maxindex] < arr[i] ? i : maxindex;//找出最高的山峰
	}
	int res=0;
	stack<pair<int, int>> dull;
	dull.push({ arr[maxindex], 1 });//环形山峰,左边界无法确定,从最高山峰开始遍历,保证其他山峰一定有左边界
	int index=(maxindex+1)%arr.size();
	while (index != maxindex)
	{
		while (arr[index]>dull.top().first)//当当前山峰比栈顶山峰大时,找到右边界,求出栈顶山峰所在范围内的可以互相看到的山峰对,只找出与小山峰对应的高山峰就可以找出所有可以互相看到的山峰对数
		{
			pair<int, int> temp = dull.top();
			dull.pop();
			res += getteam(temp.second) + 2 * temp.second;
		}
		if (arr[index] == dull.top().first)
			dull.top().second++;
		else
			dull.push({ arr[index], 1 });
		index = (index + 1) % arr.size();
	}
	while (!dull.empty())
	{
		pair<int, int> temp = dull.top();
		dull.pop();
		res += getteam(temp.second);
		if (!dull.empty())
		{
			res += temp.second;
			if (dull.size() > 1)//栈大于2时,通过当前山峰可以找到两对山峰
				res += temp.second;
			else//栈小于2时,如果最高峰有两座,则有两对山峰,否则只有一对山峰
				res += dull.top().second > 1 ? temp.second:0;
		}
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值