主题4:攒青豆

98 阅读3分钟

当青训营遇上码上掘金

背景

       攒青豆这道题是典型的“接雨水”这道题的转型题,青训营的运营团队把雨水换成青豆真是太有想象力了,完美诠释了每位青训营同学寒假的生活状态,哈哈哈哈(希望我“攒青豆”的输入为[7,0,0,0,0,0,0,0,0,0,0,7](手动狗头))。 

思路解析

       首先说一下看到这道题的两个切入面,一个是横向即先从下往上,再从左往右挨个判断每个位置是否可以放下青豆,一个是纵向即从左到右遍历数组,判断每列可以攒下的青豆数量。 

       横向的算法其实是一种暴力解法,先设结果int res = 0。由于左右2侧不可能攒下青豆,所以每次计算从第二列开始,倒数第二例结束。从下到上每行遍历,以第n行为例,从左到右遍历每一行的柱子。如果这列柱子的高度小于n,并且这列的左右都有大于等于n的柱子,res++。最后直到最高柱子一行截止,得到的res即为最终的结果,时间复杂度O(m*n)。 

       纵向的算法在一定程度上做了很大的优化,只从左到右遍历一次数组,计算得到每列柱子左右各自的最大高度,取二者中的最小值,若该值大于此列柱子高度,取二者差加入结果。

       在纵向的算法上还可以做一定程度的优化,利用双指针的思想,我们都知道水桶的短板问题,控制水桶水量的是最短的一条板子。这道题也是类似,我们可以将整个图看成一个水桶,两边就是水桶的板,中间比较低的部分就是水桶的底,由较短的边控制水桶的最高水量。但是水桶中可能出现更高的边,比如上图第四列,它比水桶边还要高,那这种情况下它是不是将一个水桶分割成了两个水桶,而中间的那条边就是两个水桶的边。

       最终我们得到的算法的编程结果如下所示:

import java.util.*;
public class Solution {
    public long maxWater (int[] arr) {
        //排除空数组
        if (arr.length == 0) 
            return 0;
        long res = 0;
        //左右双指针
        int left = 0; 
        int right = arr.length - 1; 
        //中间区域的边界高度
        int maxL = 0; 
        int maxR = 0;
        //直到左右指针相遇
        while (left < right){ 
            //每次维护往中间的最大边界
            maxL = Math.max(maxL, arr[left]); 
            maxR = Math.max(maxR, arr[right]);
            //较短的边界确定该格子的水量
            if(maxR > maxL) 
                res += maxL - arr[left++]; 
            else
                res += maxR - arr[right--];
        }
        return res;
    }
}

问题

       给出的结果是leetcode模式下的算法过程,而对于acm模式还要考虑其输入输出,我在我的码上掘金上给出了如下的代码,在本地IDEA上可以顺利运行,但是码上掘金平台一直下图所示报错,希望日后能够找到原因吧。

/** * 支持 import Java 标准库 (JDK 1.8) */import java.util.*;/** * 注意:目前 Java 代码的入口类名称必须为 Main(大小写敏感) */public class Main {    private static Scanner sc = new Scanner(System.in);    public static void main(String []args) {        //处理输入部分,得到对应的数组        //Scanner sc = new Scanner(System.in);        String str1 = sc.next();        str1 = str1 + sc.next();        str1 = str1 + sc.next();        sc.close();        int n = str1.length();        String str = str1.substring(8, n - 1);        String[] arr = str.split(",");        int[] heights = new int[arr.length];        for (int i = 0; i < heights.length; i++) {            heights[i] = Integer.parseInt(arr[i]);        }        //处理过程        int res = 0, len = heights.length;        int i = 0, j = len - 1;        int maxL = heights[0], maxR = heights[j];        while (i < j) {            maxL = Math.max(maxL, heights[i]);            maxR = Math.max(maxR, heights[j]);            if (maxL < maxR) {                res += (maxL - heights[i]);                i++;            } else {                res += (maxR - heights[j]);                j--;            }        }        //sc.close();        System.out.println(res);    }}