法一:前缀和
求能装多少水,即左右两边木板高度的最小值减去数组元素。左边木板高度即左区间最大高度,右边木板高度即右区间最大高度。第一个数组存储从最左边到第i个位置的最大高度(前缀最大值),第二个数组存储从最右边到第i的位置的最大高度(后缀最大值)。对于当前位置的前缀最大值 = max(前一个位置的前缀最大值,当前位置的最大高度)。每一个位置的前后缀数组里的值的最小值减去数组中的数值即水
cpp
class Solution {
int pre_max[20010];
int suf_max[20010];
public:
int trap(vector<int>& nums) {
int n = nums.size();
pre_max[0] = nums[0];
for (int i = 1; i < n; ++i)
pre_max[i] = max(pre_max[i - 1], nums[i]);
suf_max[n - 1] = nums[n - 1];
for (int i = n - 2; i >= 0; --i)
suf_max[i] = max(suf_max[i + 1], nums[i]);
int ret = 0;
for (int i = 0; i < n; ++i)
{
ret += min(pre_max[i], suf_max[i]) - nums[i];
}
return ret;
}
};
法二:优化为双指针(好处,不用创建数组)
前缀最大值 > 后缀最大值,则最大高度为后缀最大值,水量为这个最大高度减去数组元素,右指针左移
cpp
class Solution {
public:
int trap(vector<int>& nums) {
int n = nums.size();
int pre_max = 0, suf_max = 0;
int left = 0, right = n - 1;
int ret = 0;
while (left <= right)
{
pre_max = max(pre_max, nums[left]);
suf_max = max(suf_max, nums[right]);
if (pre_max < suf_max)
{
ret += pre_max - nums[left++];
}
else ret += suf_max - nums[right--];
}
return ret;
}
};