题意:
- 将一个数组看成柱子高度,求柱子组成的容器最多能装的水的量。
方法一:
- 记录左侧最高柱子以及右侧最高柱子,蓄水的条件是两侧的高度取较小的值。因此取两者的较小值,减去当前值即为接雨水的值。
图解如下:
- 输入: [3,1,2,5,2,4]
红色线表示左侧最高柱子,黄色线表示右侧最高柱子,黄色部分表示两者最小值构成的区域,紫色部分表示装水值。 - 结果:5
代码如下:
class Solution {
public:
/**
* max water
* @param arr int整型vector the array
* @return long长整型
*/
long long maxWater(vector<int>& arr) {
// write code here
vector<int> leftStart,rightStart;
int maxHeight=arr[0],n=arr.size();
//从左向右不减的数组,表示左侧最高柱子
for(int i=0;i<n;i++){
maxHeight=max(arr[i],maxHeight);
leftStart.push_back(maxHeight);
}
//从右向左不减的数组,表示右侧最高柱子
maxHeight=arr[n-1];
for(int i=n-1;i>=0;i--){
maxHeight=max(arr[i],maxHeight);
rightStart.push_back(maxHeight);
}
//利用三个数组的关系计算得到结果
long long ans=0;
for(int i=0;i<n;i++){
//蓄水的条件是满足短板,即左右侧最高柱子的较小值。
ans+=min(leftStart[i],rightStart[n-1-i])-arr[i];
}
return ans;
}
};复杂度分析:
时间复杂度:,n为数组arr长度,遍历数组常数次。
空间复杂度:,额外的两个长度为n的数组leftStart,rightStart。
方法二:
- 使用单调递减栈,一层一层的计算接雨水的量。如题目中的图所示:
- 用一个单调递减栈从左往右存柱子的高度。如上图应该前两个元素是3,1。第三个元素是2,不符合单调递减栈的要求,如果栈中的元素大于等于两个,在此处就是3,1。3,1,2组成了一个容器,该容器的蓄水量是
。同理遍历至下一个则是
。
代码如下:
class Solution {
public:
/**
* max water
* @param arr int整型vector the array
* @return long长整型
*/
long long maxWater(vector<int>& arr) {
// write code here
long long ans=0,cur=0;
//栈s存的是数组arr的下标
stack<int> s;
while(cur<arr.size()){
//当前元素不满足单调递减栈的要求,求组成的容器的蓄水量
while(!s.empty()&&arr[s.top()]<arr[cur]){
int last=s.top();
s.pop();
//栈中的元素只有一个,不能组成蓄水的条件
if(s.empty())
break;
//计算当前求的蓄水的长度和宽度
long long length=cur-s.top()-1;
long long height=min(arr[cur],arr[s.top()])-arr[last];
ans+=length*height;
}
//当前元素满足单调递减栈的要求,直接入栈
s.push(cur++);
}
return ans;
}
};复杂度分析:
时间复杂度:,n为数组arr长度,遍历数组一次,每个元素出入栈操作共两次 。
空间复杂度:,单调递减栈的最大空间要求n。
方法三:
- 对方法一的leftStart,rightStart数组,其目的是用于记录左侧和右侧最大值。可以使用两个变量来替代,以此降低空间复杂度。
- 双指针left,right分别从左向右和从右向左移动,leftMax,rightMax分别记录左侧最大值和右侧最大值。leftMax<rightMax时,则雨水取决于左,那么计算leftMax-arr[left]值即为接雨水的量,反之类似。while循环直到left>=right,遍历数组arr,返回结果ans。
class Solution { public: /** * max water * @param arr int整型vector the array * @return long长整型 */ long long maxWater(vector<int>& arr) { // write code here long long ans=0; int left=0,right=arr.size()-1; //利用两个变量leftMax,rightMax来记录左右柱子的最大值 int leftMax=arr[left],rightMax=arr[right]; while(left<right){ //左高度小于右高度,则雨水取决于左,否则取决于右。 if(leftMax<rightMax){ //计算接雨水的值并更新left和leftMax ans+=leftMax-arr[left]; left++; leftMax=max(leftMax,arr[left]); }else{ //计算接雨水的值并更新right和rightMax ans+=rightMax-arr[right]; right--; rightMax=max(rightMax,arr[right]); } } return ans; } };复杂度分析:
时间复杂度:,遍历数组arr。
空间复杂度:,常数个临时变量。



京公网安备 11010502036488号