给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器,且 n 的值至少为 2。
图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例:
输入: [1,8,6,2,5,4,8,3,7]
输出: 49
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/container-with-most-water
整体思路:将每条边作为短边,寻找另一条距离它最远的长边(长边>=短边)
题解1:双指针方法,参考了leetcode的想法,确实比较简洁,也符合我的思路;
// 16ms 左右,时间复杂度:O(n)
class Solution {
public:
int maxArea(vector<int>& a) {
int ans=0;
int l=0,r=a.size()-1;
while(r>l){
ans=max(ans,min(a[l],a[r])*(r-l));
if(a[l]<=a[r]) l++;
else r--;
}
return ans;
}
};
题解2:用线段树维护,第一思路就是这个了,写起来比较麻烦;
范围变成了 1 …… n ,我将 vector<>a,整体向后移了一位,因为我写线段树习惯将根设为 1。
对 a 中每个位置值 x 要进行两次线段树查询,第一次查询在其左边且最靠前 >= x 的位置;
第二次查询在其右边且最靠后 >= x 的位置;
// 56ms左右,时间复杂度:O(n*logn)
class Solution {
public:
int tree[40005],index=-1; // tree[]:存放树,index代表每次查出来的位置
void sett(int l,int r,int rt,vector<int>& a){ // 建树,这里线段树维护的是每个区间最大
if(l==r){ // 值的下标位置
tree[rt]=l;
return ;
}
int mid=l+r>>1;
sett(l,mid,rt<<1,a);
sett(mid+1,r,rt<<1|1,a);
if(a[tree[rt<<1]]>a[tree[rt<<1|1]]) tree[rt]=tree[rt<<1];
else tree[rt]=tree[rt<<1|1];
}
// flag 为 false 代表左查找;flag 为 ture 代表右查找
void findd(int x,int px,int py,int l,int r,int rt,vector<int>& a,bool flag){
if(index!=-1) return ; // 找到后,返回
if(l==r){ // 找到底部
if(px<=l&&l<=py) index=l; // 判断找到的是否在符合的区间范围
return ;
}
int mid=l+r>>1;
if(!flag){
// 左查找:代表尽量向左边查找,先查左再查右
if(a[tree[rt<<1]]>=a[x]) findd(x,px,py,l,mid,rt<<1,a,flag);
if(a[tree[rt<<1|1]]>=a[x]) findd(x,px,py,mid+1,r,rt<<1|1,a,flag);
}
else{
// 右查找:代表尽量向右边查找,先查右再查左
if(a[tree[rt<<1|1]]>=a[x]) findd(x,px,py,mid+1,r,rt<<1|1,a,flag);
if(a[tree[rt<<1]]>=a[x]) findd(x,px,py,l,mid,rt<<1,a,flag);
}
}
int maxArea(vector<int>& a) {
a.push_back(0);
for(int i=a.size()-1;i>=0;i--) a[i+1]=a[i]; // 范围向后移一格
sett(1,a.size(),1,a); // 建树
int ans=0;
for(int i=1;i<a.size();i++){
index=-1;
findd(i,1,i,1,a.size(),1,a,false); // 左查
int l=index;
index=-1;
findd(i,i,a.size(),1,a.size(),1,a,true); // 右查
int r=index;
ans=max(ans,(r-i)*a[i]);
ans=max(ans,(i-l)*a[i]);
}
return ans;
}
};