首页 > 试题广场 >

接雨水问题

[编程题]接雨水问题
  • 热度指数:92095 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给定一个整形数组arr,已知其中所有的值都是非负的,将这个数组看作一个柱子高度图,计算按此排列的柱子,下雨之后能接多少雨水。(数组以外的区域高度视为0)


数据范围:数组长度 ,数组中每个值满足 ,保证返回结果满足
要求:时间复杂度
示例1

输入

[3,1,2,5,2,4]  

输出

5 

说明

数组 [3,1,2,5,2,4] 表示柱子高度图,在这种情况下,可以接 5个单位的雨水,蓝色的为雨水 ,如题面图。          
示例2

输入

[4,5,1,3,2]

输出

2 

递归解法

void del(int fir,int end,int*arr){
    if(end-fir<=1) return;
   
        while(1){
        if(arr[fir]==0){
            for(int j=fir+1;j<end;j++){
                if(arr[j]>0){
                    del(j,end,arr);
                    break;
                }

            }
            break;
        }
        if(arr[end]==0){
            for(int j=end;j>fir;j--){
                if(arr[j]>0){
                    del(fir,j,arr);
                    break;
                }

            }
            break;
        }
        int k=arr[fir]>arr[end]?arr[end]:arr[fir];
        for(int i=fir;i<=end;i++){
            arr[i]-=k;
        }
   
        }
}


long long maxWater(int* arr, int arrLen ) {
    // write code here
    del(0,arrLen-1,arr);
    long long sum=0;
    for(int i=0;i<arrLen;i++){
        if(arr[i]<0){
            sum-=arr[i];
        }
    }
    return sum;
}
发表于 2023-05-13 10:52:57 回复(0)
long long maxWater(int* arr, int arrLen ) {
    // write code here
    if(arrLen<3)return 0;
    ////////////////////////////
    int left = 0;
    int right = arrLen-1;
    long long water = 0;
    long long temp = 0;
    
    while(left < right){
        if(arr[left]<=arr[right]){
            temp = arr[left];
            while(arr[left]<=arr[right]){
                left++;
                if(temp-arr[left] > 0)water += temp-arr[left];
                else break;
            }
        }
        else{
            temp = arr[right];
            while(arr[left]>=arr[right]){
                right--;
                if(temp-arr[right] > 0)water += temp-arr[right];
                else break;
            }
        }
    }
    
    return water;
}
发表于 2022-03-12 18:06:12 回复(0)
/**
 * 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;
}

发表于 2022-03-11 00:07:00 回复(0)
/**
 * 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;
}

发表于 2021-09-27 21:04:38 回复(0)

问题信息

难度:
4条回答 8728浏览

热门推荐

通过挑战的用户