当青训营遇上码上掘金 | 主题 4:攒青豆

99 阅读2分钟

当青训营遇上码上掘金

选择主题4:攒青豆

这是第五届字节跳动青训营的活动任务之一,选择一道算法题进行解答。

对于第四题攒青豆问题,其实就是接雨水问题。

具体的题解可以看力扣的42题接雨水题解区,包括有动态规划、双指针、单调栈等解决方法。

下面选择比较容易理解和记忆的双指针法解决这道题,java语言实现具体算法。

问题:

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

image.png

案例:

image.png

过程:

  • for循环从左侧看
  • for循环从右侧看
  • for循环计算高低-height高度

代码:

   public static void main(String []args) {
     int[] height = new int[]{5,0,2,1,4,0,1,0,3};
     System.out.println(solution(height));  
   }
   public static int solution(int[] height){
       int res = 0;
       int n = height.length;
       if(n < 3) return 0;
       int[] left = new int[n];
       int[] right = new int[n];
       left[0] = height[0];
       right[n-1] = height[n-1];
       for(int i = 1; i < n; i++){//从左看
           left[i] = Math.max(left[i-1], height[i]);
       }
       for(int i = n - 2; i >= 0; i--){//从右看
           right[i] = Math.max(right[i+1], height[i]);
       }
       for(int i = 0; i < n; i++){
           res +=  Math.min(left[i], right[i]) - height[i];
       }
       return res;
    }
 }

复杂度:

  • 时间复杂度:O(n)。
  • 空间复杂度:O(1)。

解释:

  • 初始化两个数组left[ ]right[ ],记录下从左看到的最大柱子高度和从右边看到的最大柱子高度。left值为max(height[0],...,height[i]), right的值为max(height[i],...,height[n-1])
  • 左右两边看到的最大值减去本柱子高度,即可得本柱子能存储的豆子数量。因为本柱子能存的豆子数量等于它左边右边高度减去本柱子的高度。i_count=min(left_max, right_max)-height[i]
  • 接雨水问题换壳,能接的豆子数量也就是雨水高度是由 height[left] 和 height[right] 较小的值决定的,所以取min减去height[i]。
  • 遍历输入数组三次,所以时间复杂度为O(n)
  • 存储了两个定长数组,长度为n,所以时间复杂度为O(1)

问题: