给定一个整形数组arr,已知其中所有的值都是非负的,将这个数组看作一个柱子高度图,计算按此排列的柱子,下雨之后能接多少雨水。(数组以外的区域高度视为0)
数据范围:数组长度 ,数组中每个值满足 ,保证返回结果满足
要求:时间复杂度
[3,1,2,5,2,4]
5
数组 [3,1,2,5,2,4] 表示柱子高度图,在这种情况下,可以接 5个单位的雨水,蓝色的为雨水 ,如题面图。
[4,5,1,3,2]
2
/** * max water * @param arr int整型一维数组 the array * @param arrLen int arr数组长度 * @return long长整型 * * C语言声明定义全局变量请加上static,防止重复定义 */ //双指针法 int min(int a, int b) { return a < b? a:b; } long long maxWater(int* arr, int arrLen ) { // write code here int sum = 0; int left = 0, right = 0; int count = 0;//统计指针之间的格子个数 int max = 0, max_pos;//记录右指针远离左指针过程中出现的最大值及坐标 while(left < arrLen - 1) { count = 0; max = 0; max_pos = arrLen - 1; //每次开始时左指针遇到非降时就直接向前移动 while(*(arr + left) <= *(arr + left + 1)) { left ++; } //右指针一直移动到不低于左指针的位置 right = left + 1; while(*(arr + right) < *(arr + left) && right < arrLen - 1) { //最大值的记录 if(*(arr + right) > max) { max = *(arr + right); max_pos = right; } count += *(arr + right); right ++; } //如果右指针直接移动动了数组边界 if(right == arrLen - 1) { //将它与最大值作比较从而根据情况作下一步判断 if(*(arr + right) >= max)//理想情况,如果最大值在数组边界处 { sum += (right - left - 1) * min(*(arr + left),*(arr + right)) - count; break; } else { //否则right指针回溯到最大值所在地方 for(right -= 1;right >= max_pos; right --) { count -= *(arr + right); } right = max_pos; } } sum += (right - left - 1) * min(*(arr + left),*(arr + right)) - count; left = right; } return sum; }
/** * max water * @param arr int整型一维数组 the array * @param arrLen int arr数组长度 * @return long长整型 */ /*这个题可以这样来理解,从“第一个”开始,我们需要找到一个比它高的“木板”, 这样就能存储下雨水,如果没有比它高的,那就找到除它之外最高的,与它构成一个凹槽。 计算出这个凹槽的储水量。 然后再以刚找到的“木板”当“第一个”,重复上述操作。 */ long long maxWater(int* arr, int arrLen) { // write code here int i = 0; int tmp = 0;//用来记忆遍历数组的最大值 int j = 0; long long num = 0;//雨水数 int pos = -1;//用来记住遍历数组最大值的位置 while (i<arrLen-1) { j = i + 1;//为什么不放入循环呢?因为如果放入,第二次使用循环时这个语句就不会被使用。 for ( ; j<arrLen; j++)//寻找“第一个”后面最高的 { if (arr[j]>tmp)//把过程中大的值记录下来,这样如果后面找不到比“第一个”高的木板时,我们不必再重头找除“第一个”之外最高的木板了。 { tmp = arr[j]; pos = j;//记录下位置 } if (arr[j] >= arr[i]) { for (int n = i; n<j; n++)//找到后计算储水量。 { num = num + arr[i] - arr[n]; tmp = 0; } i = j; break; } } if (j >= arrLen)//这说明没有找到比“第一个”高的 { j = i + 1; for (; j<pos; j++) { num = num + tmp - arr[j];//计算储水量时以tmp为标准。 } i = pos; tmp = 0; } } return num; }