问题一
问题描述:
假设一个数组A[n]的n个元素都是非负整数的,(i,A[i])(0<=i<n)表示在X轴上i位置有高为A[i]的“墙”(假设墙的厚度为0),求n堵“墙”中任意两堵“墙”和X轴组成的容器的最大容水量。
例如,int A[] = {2,4,3};则任意两堵“墙”与X轴可以组成的最大容水量为:4
算法思想
由数组的两头向中间遍历,忽略比当前容器较矮的“墙”还要矮的墙。时间复杂度O(n),空间复杂度O(1).
实现
/**
最大容水量:
墙没有宽度,求任意两堵墙和X轴组成的容器的最大值。
*/
int maxArea(vector<int> &height) {
int bidx,eidx,maxarea;
bidx = 0;
eidx = height.size()-1;
maxarea = 0;
while(bidx<eidx){
if(height[bidx]>=height[eidx]){
maxarea = max(maxarea,height[eidx]*(eidx - bidx));
eidx--;
}else{
maxarea = max(maxarea,height[bidx]*(eidx - bidx));
bidx++;
}
}
return maxarea;
}
问题二
问题描述
和问题一类似,数组元素的大小是非负数,代表墙的高度,墙的厚度为0。不过不是要求最大的容水量,而是要求总的容水量。
例如,int A[] = {2,4,3};则总的容水量为:5
算法思想
和问题一的思想类似,也是有由数组两边向中间遍历,忽略比当前容器较矮“墙”还要矮的墙,将可以确定容量的部分的容量累加到总的容量上。时间复杂度为O(n),空间复杂度为O(1)
实现
/**
总容水量:
墙没有宽度,求总的容水量
*/
int sumArea(vector<int> &height){
int bidx,eidx,pidx,sum;
bidx = 0 ;
eidx = height.size()-1;
sum = 0;
while(bidx<eidx){
if(height[bidx]>=height[eidx]){
pidx = eidx - 1;
while(pidx>bidx && height[pidx]<height[eidx]){
pidx--;
}
sum += min(height[eidx],height[pidx])*(eidx - pidx);
eidx = pidx;
}else {
pidx = bidx + 1;
while(pidx<eidx && height[pidx]<height[bidx]){
pidx++;
}
sum += min(height[bidx],height[pidx])*(pidx - bidx);
bidx = pidx;
}
}
return sum;
}
问题三
问题描述
同样是非负数组A[n],元素值代表墙的高度,但墙的厚度为1,且墙是依次挨着的,求总的容水量。
例如,int A[] = {2,4,3}; 则总的容水量为:0
又如:
int A[] = {4,2,3,4};则总的水容量为:3
算法思想
和问题二的思想类似,不过在遍历的过程中需要记录要减去的总容量(既被忽略墙的高度和),如果上面第二个图最终的结果实际上是8-(2+3) = 3。时间复杂度为O(n),空间复杂度为O(1).
实现
/*
总容水量:
墙的宽度为1,求总的总容水量
*/
int sumAreaW1(vector<int> &height){
if(height.size()<=2){//少于三堵墙 都不可能存水
return 0;
}
int bidx,eidx,sum,pidx;
bidx = 0;
eidx = height.size()-1;
sum = 0;
int tmpsum = 0;
while(height[bidx+1]>=height[bidx] && bidx+1<height.size()){
bidx++;
}
while (height[eidx-1]>=height[eidx] && eidx-1>=0){
eidx--;
}
while(bidx<eidx-1){
if(height[bidx]>=height[eidx]){
pidx = eidx - 2;
tmpsum += height[eidx-1];
while(pidx>bidx && height[pidx]<height[eidx]){
tmpsum += height[pidx];
pidx--;
}
sum += min(height[eidx],height[pidx])*(eidx - pidx -1) - tmpsum;
eidx = pidx;
tmpsum = 0;
}else{
pidx = bidx + 2;
tmpsum += height[bidx+1];
while(pidx<eidx && height[pidx]<height[bidx]){
tmpsum += height[pidx];
pidx++;
}
sum += min(height[bidx],height[pidx])*(pidx - bidx - 1) - tmpsum;
bidx = pidx;
tmpsum = 0;
}
}
return sum;
}
};
测试程序和测试结果
测试程序
int main(){
Solution sln;
int A0[] = {2,4,3,5,7};
vector<int> height0(A0,A0+5);
cout<<"maxArea:"<<sln.maxArea(height0)<<endl;
cout<<"sumArea:"<<sln.sumArea(height0)<<endl;
cout<<"sumAreaW1:"<<sln.sumAreaW1(height0)<<endl;
cout<<"-------------"<<endl;
int A2[] = {2,4,3};
vector<int> height2(A2,A2+3);
cout<<"maxArea:"<<sln.maxArea(height2)<<endl;
cout<<"sumArea:"<<sln.sumArea(height2)<<endl;
cout<<"sumAreaW1:"<<sln.sumAreaW1(height2)<<endl;
cout<<"-------------"<<endl;
int A3[] = {2,4,3,7};
vector<int> height3(A3,A3+4);
cout<<"maxArea:"<<sln.maxArea(height3)<<endl;
cout<<"sumArea:"<<sln.sumArea(height3)<<endl;
cout<<"sumAreaW1:"<<sln.sumAreaW1(height3)<<endl;
cout<<"-------------"<<endl;
int A4[] = {5,4,3,7,9,2};
vector<int> height4(A4,A4+6);
cout<<"maxArea:"<<sln.maxArea(height4)<<endl;
cout<<"sumArea:"<<sln.sumArea(height4)<<endl;
cout<<"sumAreaW1:"<<sln.sumAreaW1(height4)<<endl;
cout<<"-------------"<<endl;
int A5[] = {5,4,5};
vector<int> height5(A5,A5+3);
cout<<"maxArea:"<<sln.maxArea(height5)<<endl;
cout<<"sumArea:"<<sln.sumArea(height5)<<endl;
cout<<"sumAreaW1:"<<sln.sumAreaW1(height5)<<endl;
cout<<"-------------"<<endl;
int A6[] = {5};
vector<int> height6(A6,A6+1);
cout<<"maxArea:"<<sln.maxArea(height6)<<endl;
cout<<"sumArea:"<<sln.sumArea(height6)<<endl;
cout<<"sumAreaW1:"<<sln.sumAreaW1(height6)<<endl;
cout<<"-------------"<<endl;
int A7[] = {5};
vector<int> height7(A7,A7+0);
cout<<"maxArea:"<<sln.maxArea(height7)<<endl;
cout<<"sumArea:"<<sln.sumArea(height7)<<endl;
cout<<"sumAreaW1:"<<sln.sumAreaW1(height7)<<endl;
cout<<"-------------"<<endl;
int c;
cin>>c;
}
测试结果
总结
上面三个问题的解法是类似的,要做到时间复杂度为O(n),空间复杂度为O(1),关键思路是由数组两边向中间遍历,忽略一些该忽略的容器。