当青训营遇上码上掘金
题目介绍
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
题目解法
本题的解法其实多种多样,一般主流解法为动态规划,暴力,单调栈以及双指针法。在这道题中,博主的解法主要是双指针方法,控制时间复杂度在O(n)内,空间复杂度O(1)。
在这个题目中,我们使用双指针来遍历数组,只考虑当前有可能的最优解。
我们可以使用两个指针,一个指针从左向右扫描,另一个指针从右向左扫描。在左指针扫描时,如果遇到高度小于等于左指针所指高度,则相互做差更新青豆数,如果遇到高度大于左指针所指高度,则继续上述行为,相互做差更新青豆数。在右指针扫描时,如果遇到高度小于等于右指针所指高度,则相互做差更新青豆数,如果遇到高度大于右指针所指高度,则青豆数此次更新为0。然后我们计算当前所有可能的存储量,并更新答案。将两个指针中各移动一位,继续扫描。这样我们就能有效减少比较次数和提高效率。
public class Main {
public static int saveGreenBeans(int[] height) {
if (height == null || height.length <= 2) {
return 0;
}
int count = 0;
int N = height.length;
int leftMax = height[0];
int rightMax = height[N - 1];
int L = 1;
int R = N - 2;
while(L <= R) {
if (leftMax <= rightMax) {
count += Math.max(0, leftMax - height[L]);
leftMax = Math.max(leftMax, height[L++]);
} else {
count += Math.max(0, rightMax - height[R]);
rightMax = Math.max(rightMax, height[R--]);
}
}
return count;
}
public static void main(String []args) {
int[] height = new int[]{5,0,2,1,4,0,1,0,3};
int count = saveGreenBeans(height);
System.out.println(count);
}
}
这段代码中,我们首先初始化左右指针 L 和R。然后,我们使用两个变量 leftMax 和 rightMax 记录当前数组中的最大值(初始值leftMax为height[0],rightMax为height[N - 1]),并使用一个变量 count 来记录青豆的最大数量。
在 while 循环中,我们比较两个指针所指向的位置的高度,如果左指针所指向的高度小于等于右指针所指向的高度,则说明左指针所指向的位置是当前左右最大值最小的,我们将 leftMax - 当前遍历到数组值如果大于0我们就更新青豆数否则青豆数加0,同时比较当前值和leftMax继而更新leftMax然后左指针加加。否则,右指针所指向的位置是当前左右最大值最小的,我们将 rightMax - 当前遍历到数组值如果大于0我们就更新青豆数否则青豆数加0,同时比较当前值和rightMax继而更新rightMax然后右指针加加。最后,我们移动左右指针直到两个指针错过。 这道题双指针的时间复杂度是O(n)。因为每个位置被访问和处理最多一次,所以总的时间复杂度为O(n)。空间复杂度是O(1)
因为博主平常写文章很少,所以有不足还望大家指出!!!