单调栈,一种可以找到左右边界的数据结构
//利用单调栈找到一个数的左边最近的比他小的数(左边界)和右边最近的比他小的数(右边界)
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;
}
}
}