题目链接:LCR 039. 柱状图中最大的矩形 - 力扣(LeetCode)
首先我写题喜欢暴力解法,可以先尝试一下枚举的方法。
这里有两种
第一种:
#include <iostream>
#include <stack>
#include <vector>
using namespace std;
typedef pair<int, int> PII;
int main() {
int n;
cin >> n;
vector<int>v(n);
int ans = -1;
int result = 0;
for (int i = 0; i < n; i++) {
cin >> v[i];
}
//遍历枚举高的算法
int mid = 0;
for (; mid < n; mid++) {
int left = mid;
int right = mid;
while (left-1 >= 0 && v[left - 1] >= v[mid]) {
left--;
}
while (right+1<=n-1 && v[right + 1] >= v[mid]) {
right++;
}
ans = max(ans, (right - left + 1) * v[mid]);
}
cout << ans << endl;
return 0;
}
遍历枚举每一条高线然后从头枚举到尾巴,然后利用循环找到,比他小的两条柱子
但是很显然会超时
第二种方法:
确定宽度,定义一个变量不断的去找最小的高度长度
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <stack>
#include <vector>
using namespace std;
typedef pair<int, int> PII;
int main() {
int n;
cin >> n;
vector<int>v(n);
int ans = -1;
int result = 0;
for (int i = 0; i < n; i++) {
cin >> v[i];
//遍历枚举宽的算法
int left = 0;
int right = 0;
int min_high = v[0];
for (left; left < n;left++) {
min_high = INT32_MAX;//重塑一遍,因为不能保留上次的数据
for (right=left; right < n; right++) {
min_high = min(v[right], min_high);
result = min_high * (right - left + 1);
ans = max(ans,result);
}
}
cout << ans << endl;
return 0;
}
这里要注意的是,left的变化,记得变化高
然后就是本题的核心思想,单调栈,怎么想出来的呢,就是,请看第一种方法,就是找到比当前小的高,也就是如果,i<j,并且h[i]>h[j]的话,那么我们可以认为,我们在找,就j+1的柱子高度小的柱子,就没有必要在找i了,所以想到用单调栈
先来一个错误的写法(没有实现,当比较完之后,栈里面剩下的数字的处理,以及很难处理,开始的矩形高度是0的问题)
ps:可能是使用的方法不不对,就是利用栈<pair>储存东西
typedef pair<int, int> PII;
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int n = heights.size();
int ans = -1;
int result = 0;
stack<PII>s;
s.push(PII(0, heights[0]));
int Index = 1;//访问元素下标
while (Index < n) {
if (heights[Index] >= s.top().second) {
s.push(PII(Index, heights[Index]));
Index++;
}
else {
result = (Index - (s.top().first))*(s.top().second);
ans = max(result, ans);
s.pop();
}
if (s.empty()) {
result = (Index +1) *heights[Index];
ans = max(result, ans);
s.push(PII(Index,heights[Index]));
Index++;
}
}
int bottle = 0;
int bottleHigh = 0;
if (!s.empty()) {
int top = s.top().first;
while (!s.empty()) {
if(s.top().second!=0)
bottle = s.top().first;
if(s.top().second!=0)
bottleHigh = s.top().second;
s.pop();
}
result = (top - bottle + 1) * bottleHigh;
ans = max(ans, result);
}
return ans;
}
};
其实不难发现,一开始的代码连题解的意思都没有搞懂,这个是类比方法一中的方法,去,模拟方法一然后去,找到对应的长度。
改进之后的代码,用vector存储,left和right,以及只用stack来存储相应的下标
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int n = heights.size();
int ans = -1;
int result = 0;
stack<int>s;
vector<int>left(n);
vector<int>right(n);
for (int i = 0; i < n; i++) {
if (!s.empty() && heights[i] >heights[s.top()]) {
left[i] = i - 1;
s.push(i);
}
else {
if (!s.empty()) {
while (!s.empty()&&heights[i]<=heights[s.top()]) {
s.pop();
}
}
left[i] = (s.empty() ? -1 : s.top());
s.push(i);
}
}
s = stack<int>();
for (int i = n-1; i >= 0; i--) {
if (!s.empty() && heights[i] > heights[s.top()]) {
right[i] = i + 1;
s.push(i);
}
else {
if (!s.empty()) {
while (!s.empty() && heights[i] <= heights[s.top()]) {
s.pop();
}
}
right[i] = (s.empty() ? n : s.top() );
s.push(i);
}
}
for (int i = 0; i < n; i++) {
result = (right[i] - left[i] - 1) * heights[i];
ans = max(ans, result);
}
return ans;
}
};
有几个地方很重要
如图
然后就是一些小细节
清空栈啊,!empty()要放当成优先级最高的条件,不然可能会访问越界
然后就是一些访问越界问题,注意一下就好了
下面是官方代码:比我的简洁但我想不到