当青训营遇上码上掘金
选择主题4:攒青豆
这是第五届字节跳动青训营的活动任务之一,选择一道算法题进行解答。
对于第四题攒青豆问题,其实就是接雨水问题。
具体的题解可以看力扣的42题接雨水题解区,包括有动态规划、双指针、单调栈等解决方法。
下面选择比较容易理解和记忆的双指针法解决这道题,java语言实现具体算法。
问题:
现有n个宽度为1的柱子,给出n个非负整数依次表示柱子的高度,排列后如下所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
案例:
过程:
- 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)。
问题:
- 后续还有很多优化的方法,具体可以继续参考力扣题解。
- 链接:leetcode.cn/problems/tr…