「青训营 X 码上掘金」主题创作活动-攒青豆

100 阅读2分钟
当青训营遇上码上掘金——主题4:攒青豆

前言

由于本人是编程小白,只在学校学习了一学期的c语言和简单的算法,所以尝试用c语言解题。

题目

现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)

image.png

以下为上图例子的解析:

输入:height = [5,0,2,1,4,0,1,0,3]  
输出:17  
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度
        在这种情况下,可以接 17 个单位的青豆。 

思路

法一

在数组中任意选取一个位置i,求出i左边的最大值,i右边的最大值。i位置能装的豆子取决于2个最大值较小的一个

使用两个数组left和right,left[i]为i位置左边的最大值,将left[i-1]与height[i]比较,取最大值

二者的差值为可以装的豆子

设数组长度为heightLen,从i=1开始遍历到i=heightLen-2,每个位置的豆子总和加在一起,得到总和

注:经过测试,发现以下问题:

①该算法设计不严谨,输出数值与实际值不符,考虑新方法

②由于c语言的局限性,难以实现数组长度可变,会出现数组下标越界访问的问题,考虑用c++的vector类可变数组进行后续改进

法二

从数组两边的端点向中间遍历,记录左边的最大值leftMax和右边的最大值rightMax,当指针相遇时,停止遍历

遇到比最大值小的就+(最大值-当前值)的豆子,遇到比最大值大的就更新最大值,直到两个指针相遇

以left指针为例:

①如果height[left]比leftMax小,直接在总数上+(最大值-当前值)的豆子

②反之不能,更新leftMax的值为height[left]

因为最后一个最大值可能会多加豆,所以每次更新最大值要记录最大值的位置,计算方法同上,将两个最大值比较,按照刚才的方法重算一遍,纠正结果。

QQ图片20230113111550.jpg

代码(算法部分)

法一

#include <stdio.h>

int trap(int *height,int heightSize)
{
    if(heightSize<=2){
        return 0;
    }
    int left[heightSize], right[heightSize];
    int i,sum=0,min=0;
    left[0]=height[0],right[0]=height[0];
    for(i=1;i<heightSize;i++){
        if(height[i]>left[i-1]){
            left[i]=height[i];
        }else{
            left[i]=left[i-1];
        }
    }
    for(i=heightSize-2;i>=0;i--){
        if(height[i]>right[i+1]){
            right[i]=height[i];
        }else{
            right[i]=right[i+1];
        }
    }
    for(i=1;i<heightSize-1;i++){
        if(left[i]>right[i]){
            min=right[i];
        }else{
            min=left[i];
        }
        sum+=min-height[i];
    }
    return sum;
}

法二

#include <stdio.h>

int trap(int* height, int heightLen)
{
    if (heightLen <= 2) {
        return 0;
    }
    int left = 0, right = heightLen - 1;
    int leftMax = height[0], rightMax = height[heightLen - 1];
    int sum = 0;
    while (left <= right) {
        if (leftMax < rightMax) {
            if (height[left] < leftMax) {
                sum += leftMax - height[left];
            }
            else {
                leftMax = height[left];
            }
            left++;
        }
        else {
            if (height[right] < rightMax) {
                sum += rightMax - height[right];
            }
            else {
                rightMax = height[right];
            }
            right--;
        }
    }
    return sum;
}