当青训营遇上码上掘金 攒青豆

40 阅读1分钟

主题 4:攒青豆

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

典型的接雨水问题:使用 Java 解析

public class Main {
    public static void main(String[] args) {
        int[] height = {5,0,2,1,4,0,1,0,3};
        System.out.println(new Main().calculate(height));
    }

    public int calculate(int[] height){
        if(height.length < 2){
            return 0;
        }
        int qingdou = 0;
        for (int cursor = 0; cursor < height.length-1; cursor++) {

            // find the height after current which has the min diff with cursor
            int minDiff = Integer.MAX_VALUE;
            int minDiffIndex = -1;
            for (int i = cursor + 1; i < height.length; i++) {
                int diff = Math.abs(height[cursor] - height[i]);
                if(diff < minDiff){
                    minDiff = diff;
                    minDiffIndex = i;
                }
            }

            // calculate the qingdou
            int min = Math.min(height[cursor], height[minDiffIndex]);
            for (int i = cursor + 1; i < minDiffIndex; i++) {
                qingdou += min - height[i];
            }
            cursor = minDiffIndex - 1;

        }
        return qingdou;
    }
}

这个是常见的通过计算最小差。只是为了图块,标准解法如下5个

  1. 双指针法

双指针法是解决该问题的常用方法。我们首先找到数组中的最高柱子,然后从两侧向最高柱子所在位置分别扫描。在扫描的过程中,我们维护两个指针 left 和 right 分别指向数组的左右两端,以及两个变量 l_max 和 r_max 分别表示左右两侧当前扫描到的最高柱子高度。

  1. 初始化

在开始扫描之前,我们需要先对指针和变量进行初始化。具体来说,我们让 left 和 right 分别指向数组的两端,l_max 和 r_max 初始值均为 0。

  1. 扫描过程

在扫描的过程中,我们可以使用 while 循环来实现。在每次循环中,我们首先比较 height[left] 和 height[right] 的大小,将 l_max 和 r_max 中的最小值更新为当前较大的值。然后,如果 height[left] < height[right],则说明左侧的最高柱子不如右侧的最高柱子高,我们可以将 left 指针右移一位,并计算当前位置的雨水量(即 l_max - height[left]),将其加入总雨水量 ans 中。反之,如果 height[left] >= height[right],则说明右侧的最高柱子不如左侧的最高柱子高,我们可以将 right 指针左移一位,并计算当前位置的雨水量(即 r_max - height[right]),将其加入总雨水量 ans 中。

  1. 返回结果

在循环结束后,我们可以得到能接的雨水总量 ans,将其作为结果返回即可。

  1. 总结

双指针法是一种常用的解决该问题的方法,其时间复杂度为 O(n),空间复杂度为 O(1),非常高效。通过该方法,我们可以在不使用额外空间的情况下,求解出该问题的答案

对于该问题的复杂度分析如下:

时间复杂度:O(n)

  • 在双指针法中,我们只需要遍历一次整个数组即可,因此时间复杂度为 O(n)。

空间复杂度:O(1)

  • 在双指针法中,我们只需要使用常数个变量来维护当前的状态,因此空间复杂度为 O(1)。

综上,双指针法是一种时间复杂度为 O(n),空间复杂度为 O(1) 的高效解决该问题的方法。