题目描述
给定一个整形数组arr,已知其中所有的值都是非负的,将这个数组看作一个容器,请返回容器能装多少水。
输入描述:
第一行一个整数N,表示数组长度。
接下来一行N个数表示数组内的数。
输出描述:
输出一个整数表示能装多少水。
输入
6
3 1 2 5 2 4
输出
复制
5
思路:
对于L位置,其水平线为min{左数最大值,右侧最大值}
方法1
初始想法:先找到最高点,对于左右两边,分别依次找次高点,直到次高点为边界,每次加上次高点中间的水量(简单的说,就是从最高点向两边找“坑”)
#include<iostream>
#include<vector>
using namespace std;
#define LENGTH 1000001
int arr[LENGTH];
int getMaxID(int l, int r)
{
int max = arr[l];
int maxID = l;
for (int i = l+1; i < r; ++i)
{
if (max < arr[i])
{
max = arr[i];
maxID = i;
}
}
return maxID;
}
long long getLSum(int l, int r)
{
long long sum = 0;
for (int i = l+1; i < r; ++i)
{
sum += arr[l] - arr[i];
}
return sum;
}
long long getRSum(int l, int r)
{
long long sum = 0;
for (int i = l; i < r; ++i)
{
sum += arr[r] - arr[i];
}
return sum;
}
int main()
{
int N;
cin >> N;
long long sum = 0;
for (int i = 0; i < N; ++i)
{
cin >> arr[i];
}
int maxID = getMaxID(0, N);
int p = maxID;//左标
int q = maxID;//右表
while (p != 0)
{
int p1 = getMaxID(0, p);
sum += getLSum(p1, p);
p = p1;
}
while (q != N-1)
{
int q1 = getMaxID(q+1, N);
sum += getRSum(q+1, q1);
q = q1;
}
cout << sum;
}想法比较朴素,超时,通过90%
方法2
参考网络上的想法:由于对每个点来说,水平线都为左数组最大值和右数组最大值中较小的那个值,可以通过辅助数组记录每个点左右数组最高值,时间复杂度为O(N)。
int main()
{
int N;
cin >> N;
long long sum = 0;
vector<int> arr(N), l(N, 0), r(N, 0);
for (int i = 0; i < N; ++i)
{
cin >> arr[i];
}
for (int i = 0; i<N - 1; ++i)
{
l[i + 1] = arr[i]>l[i] ? arr[i] : l[i];
r[N - i - 2] = arr[N - i - 1] > r[N - i - 1] ? arr[N - i - 1] : r[N - i - 1];
}
for (int i = 0; i < N; ++i)
{
if (arr[i]>l[i] || arr[i] > r[i]) continue;
else if (l[i] > r[i]) sum += r[i]-arr[i];
else sum += l[i]-arr[i];
}
cout << sum;
}很好理解,并且顺利通过
方法三:
方法二中,两个辅助数组都是递推的,可以边遍历,边生成两个辅助值。
设置两个指针L和R,初始分别指向arr[1]和arr[arr.length-2]位置,指定两个变量leftMax和rightMax,初始分别为arr[0]和arr[arr.length - 1],leftMax表示[0…L-1]位置中的最大值,rightMax代表[R+1…arr.length-1]位置上的最大值。
根据leftMax与rightMax大小进行指针移动,进行遍历,可减小空间复杂度。
方法四:
XWFLS大佬的方法。直接建立水平线,每次更新,精妙极了,如下:
int main()
{
int N;
cin >> N;
long long sum = 0;
vector<int> arr(N);
for (int i = 0; i < N; ++i)
{
cin >> arr[i];
}
auto l = arr.begin();//左指针
auto r = --arr.end();//右指针
int lower = 0;
int level = 0;
while (l < r)
{
lower = *l < *r ? *l++ : *r--;
level = level>lower ? level : lower;
sum += level - lower;
}
cout << sum << endl;
}核心代码就三行,太精致了!!!

京公网安备 11010502036488号