简单单调栈的运用:
首先的话就是poj上面的一维问题,最开始的想法
当然是暴力但是自己一开始也是没有想到什么好点
的想法去暴力,那就来看下别人的想法的暴力思想吧
首先就是以一个矩形位标准,分别向左和右扩展,找到
左右第一个比他小的,中间的面积直接更新即可。
code如下:当然这个是超时的,接下来的话就是自己
学习的单调栈的应用啦
o(n^2)的超时代码:
#include<iostream>
using namespace std;
typedef long long ll;
#define M 10000
ll num[M];
int main(){
ll n,i,l,r;
while(cin>>n){
ll ans=0,res=0;
if(n==0) break;
for(i=0;i<n;i++)
scanf("%lld",&a);
for(i=0;i<n;i++){
l=i;
r=i;
while(l>=0&&num[l-1]>=a)l--;
while(r<n&&num[r+1]>=a)r++;
ans=(r-l+1)*a;
res=max(res,ans);
}
cout<<res<<endl;
}
return 0;
}
顺便学到了,
virtual oj(利用爬虫爬各oj的题目然后你就可以用一个账号写各oj的题目哟,还可以爬到国外的oj) 的话c++的头文件是不支持 c语言的scanf语句的
单调栈的代码如下:
学习到了好多的东西,了解到了单调栈不一定非要用栈写,也可以用数组模拟,有时候这种方法的效果可以更好,
还有就是学懂了那个单调栈的话,所有的元素都是最多入栈出栈一次,o(n)的时间复杂度;
数组模拟版本:
#include<iostream>
#include<stdio.h>
#include<stack>
using namespace std;
typedef long long ll;
const ll M=100100;
ll hi[M];
ll w[M];
int main(){
ll n,a,ans,top,i,cnt;
while(cin>>n){
ll top = 0; ll ans = 0;
if(n==0) break;
for(i=0;i<n;i++){
scanf("%lld",&a);
if(top==0||a>hi[top]){
w[++top] = 1;
hi[top] = a;
}
else {
cnt = 0;
while(top > 0&&a<= hi[top]){
cnt += w[top];
ans = max(ans,hi[top]*cnt);
top--;
}
hi[++top]=a;
w[top] = cnt+1;
}
/*整了半天终于弄明白为什么要用cnt来计数了,
这样就计算出了下一个 要加入的数的左边界右多少个数了;这也就是我下面代码的错误的地方
*/
/* while(top > 0&&a<= hi[top]){
ans = max(ans,hi[top]*w[top]);
w[top-1]+=w[top];
top--;
}
hi[++top]=a;
w[top] = w[top-1]+1;
}*/
}
cnt = 0;
while(top>0){
cnt += w[top];
ans = max(ans,cnt*hi[top]);
top--;
}
cout<<ans<<endl;
}
return 0;
}
//vecter容器版本;就他们直接用stack储存右边界,然后再去查找对应的高度。
//顺便系统的学习了下vecter容器;
还有一种就是左右扫描版本的,这种的话好像运用了动态规划的思想,然后做到了o(n)的时间复杂度,
这种储存结果再利用的动规是值得学习的。本人比较懒就直接看别人的博客吧;
https://www.cnblogs.com/boring09/p/4231906.html
然后就是二维的单调栈的应用了;暑假的时候写过这样的题目,再来复习一遍吧;
poj 3493题:
http://poj.org/problem?id=3494
这一题的话,自己感觉其实就是在那个上面的基础上需要压缩一下,把二维的压缩成一维的就可以了,
接下来的话其实就是在没扫完一行后就进行压栈和入栈的操作,当然这只是自己第一个的主观感受,具体的话
就需要代码来说话了。这样的想法的话就是o(n^2)的复杂度了,应该可以写吧;
哈哈哈,实践检验到自己的想法是正确的虽然代码长了点但是结果是正确的;
#include<iostream>
#include<stdio.h>
#include<stack>
using namespace std;
typedef long long ll;
ll n,m,ans,top,i,cnt,j,k;
const ll M=100100;
ll hi[M];
ll w[M];
ll a[2007];
ll ma[2007][2007];
ll check(){//check函数就是上面的一维单调栈的代码;
ll top = 0; ll ans = 0;ll d;
for(d=0;d<m;d++){
if(top==0||a[d]>hi[top]){
w[++top] = 1;
hi[top] = a[d];
}
else {
cnt = 0;
while(top > 0&&a[d]<= hi[top]){
cnt += w[top];
ans = max(ans,hi[top]*cnt);
top--;
}
hi[++top]=a[d];
w[top] = cnt+1;
}
}
cnt = 0;
while(top>0){
cnt += w[top];
ans = max(ans,cnt*hi[top]);
top--;
}
return ans;
}
int main(){
ll res;
while(cin>>n>>m){
for(j=0;j<m;j++){
scanf("%lld",&ma[0][j]);
a[j]=ma[0][j];
}
res=check();
for(j=1;j<n;j++){
for(k=0;k<m;k++){
scanf("%lld",&ma[j][k]);
if(ma[j][k]==0)a[k]=0;
else if(ma[j][k]==1){
if(a[k]!=0)a[k]++;
else a[k]=1;
}
}
res=max(res,check());
}
cout<<res<<endl;
}
return 0;
} 在这里插入代码片
组长的非常简洁的代码: https://www.cnblogs.com/wizarderror/p/11232097.html
参考博客:个人觉得他们写的好;
https://www.cnblogs.com/qixingzhi/p/9497208.html
https://www.cnblogs.com/lichen782/p/leetcode_Largest_Rectangle_in_Histogram.html
https://www.cnblogs.com/boring09/p/4231906.html