青训营 X 码上掘金-主题 4:攒青豆

77 阅读2分钟

当青训营遇上码上掘金

原题目如下:

  • 主题 4:攒青豆

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

攒青豆.png

以下为上图例子的解析:

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

思路想法

首先看到这个题的第一想法就是求面积,青豆堆积的地方其实就是这个物体形成空腔的面积,这样子想的话这个青豆数量似乎就不是那么抽象了,但是实际上还是不知道从哪里下手才好,这时候就体现出大力出奇迹的好处了,把计算的工作交给计算机哈哈哈,这样的话自己想的就会少一点,所以我首先想到了==暴力求解==

暴力求解

暴力求解的思路也很简单:就是找到一个柱子所在位置的左边的最高的和右边最高的用两者较小的减去柱子的本身的高度就是这个地方能放的青豆的数量

这样子虽然想法很简单但想想

需要每个位置都是便利寻求高度

十分的笨拙

实现代码如下

    //超时
    public int sum(int[] height) {
        int res = 0;
        //遍历所有元素,对每个元素计算其存水量,并求和
        for(int i=1; i<height.length-1; i++){
            res += find(height, i);
        }
        return res;
    }

    public int find(int[] height, int i){
        int left=0, right=0;
        //找到该元素左边最大的数
        for(int j=0; j<i; j++)
            left = Math.max(left, height[j]);
        //找到该元素右边最大的数
        for(int j=i+1; j<height.length; j++)
            right = Math.max(right, height[j]);
        //如果元素本身大于两边的数字,则无法存水,否则可以存放左右两边较小的那个数减去钙元素值大小。
        if(height[i] < left && height[i] < right)
            return Math.min(left, right) - height[i];
        else
            return 0;
    }

后来我想,, 青豆数量是由两者中的较小值决定的, 所以只要找到较少的那个即可, 没必要找到较大的那个的最大值。我们只需要两个变量去记录leftMax和rightMax,在遍历时不断更新leftMax和rightMax,其实就是一直移动较小的一边然后动态记录能装水的多少和大小。

    //88%
    public int sum(int[] A) {
        int i = 0, j = A.length - 1, result = 0, plank = 0;
        while(i <= j){
            //记录最小值
            plank = plank < Math.min(A[i], A[j]) ? Math.min(A[i], A[j]) : plank;
            //如果A[i]比较小,则将i的存水量加起来并i++,否则计算j的存水量并j++
            result = A[i] >= A[j] ? result + (plank - A[j--]) : result + (plank - A[i++]);
        }
        return result;
    }

后来我像可能还能用栈来解决哈哈哈不是很清楚