盛水最多的容器(单调栈,双指针)
题目描述
给定$n$个非负整数 $a1,a2,…,an$表示平面上有$n$条竖线,第$i$条竖线的两个端点是$(i,ai)$和$(i,0)$。
请找出两条竖线,使得它们与$x$轴组成的容器能盛最多的水。
注意:不可以把线倾斜,并且$n≥2$。
输入格式
第一行包含整数$n$。
第二行包含$n$个非负整数。
输出格式
输出一个整数,表示容器的最大盛水量。
数据范围
$1≤n≤1e5$,
$1≤ai≤1e4$。
题解
题解
$l$存储的是从当前位置往左看,最远的一个大于等于当前元素的指(存储该值在原数组中的下标), $r$ 同理.这个$l$数组里面都是一些递增的下标。
比如数组为:1 3 2 4 3 6
那么这个$l$数组中就是1,2,4,6,所以可以二分
这个也可以用双指针
Code
#include<iostream> #include<algorithm> using namespace std; const int maxn=1e6+100; int n,a[maxn],l[maxn],r[maxn]; int idx; int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; } int ans=0; for(int i=1;i<=n;i++){ int ll=1,rr=idx,pos=idx; while(rr>=ll){ int mid=(ll+rr)/2; if(a[l[mid]]>=a[i]){ rr=mid-1; pos=l[mid]; } else{ ll=mid+1; } } ans=max(ans,min(a[i],a[pos])*(i-pos)); if(i==1||a[i]>a[l[idx]]) l[++idx]=i; } idx=0; for(int i=n;i>=1;i--){ int ll=1,rr=idx,pos=idx; while(rr>=ll){ int mid=(ll+rr)/2; if(a[r[mid]]>=a[i]){ rr=mid-1; pos=r[mid]; } else{ ll=mid+1; } } ans=max(ans,min(a[i],a[pos])*(pos-i)); if(i==n||a[i]>a[r[idx]]) r[++idx]=i; } cout<<ans<<endl; }
Code2

#include <iostream> using namespace std; const int N = 100010; int a[N]; int n; int main() { scanf("%d", &n); for (int i = 0; i < n; ++i) scanf("%d", &a[i]); int l = 0, r = n - 1; int ans = 0; while (l < r) { ans = max(ans, min(a[l], a[r]) * (r - l)); if (a[l] <= a[r]) ++l; else --r; } printf("%d", ans); return 0; }