当青训营遇上码上掘金-主题4接青豆

59 阅读2分钟

当青训营遇上码上掘金,我选的是接青豆这道题目。

主题四

现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积) 示意图 经典题:接雨水的变形, 几种方案都是参考lc题解,谢谢大佬的分享,这里记录下自己的学习思考。

按行累加

基本思想:对于每个行i,从找到第一个左侧墙壁开始计数height[j] >= i,遇到height[j] < i,计数++;遇到一个中间墙壁height[j] >= i,计数合入ans,计数清零。

        for (int i = 1; i <= mx; ++i) {
            bool isvaild = false;
            int step = 0;
            for (int j = 0; j < n; ++j) {
                if (isvaild && height[j] < i) {
                    ++step;
                }
                if (height[j] >= i) {
                    isvaild = true;
                    ans += step;
                    step = 0;
                }
            }
        }

按照列累加

基本思想,找当前列i左侧的最大列leftmax,右侧最大列rightmax,当且仅当(i < min(rightmax, leftmax))时能接到豆子(即有凹槽),豆子数目为i - min(rightmax, leftmax)

            int m = min(leftmax,rightmax);
            if (height[i] < m) {
                ans += (m - height[i]);
            }

动态规划

按列累加优化,先遍历得到数组leftmax,rightmax;直接判断累加即可,这种方法lc样例执行速度最快。

        vector<int> leftmax(n,0);
        vector<int> rightmax(n,0);
        for (int i = 1; i < n; ++i) {
            leftmax[i] = max(leftmax[i-1],height[i-1]);
        }
        for (int i = n-2; i >= 0; --i) {
            rightmax[i] = max(rightmax[i+1],height[i+1]);
        }

单调栈(从大到小保存元素)

参考代码随想录

基本思想就是要找如下图所示的凹槽,遇到height[i] > height[st.top()]后需要继续取出下一位left,循环直到栈满足从大到小。

image.png 以下图为例说明 image.png

  1. 0,1,2位置正常进栈,满足从大到小
  2. height[3] > height[top()=2]
    一次循环ans+=豆2,位置2退栈;位置3进栈
  3. height[4] > height[top()=3]
    这个过程有两个循环:第一次位置3退栈;
    第二次:
    h = min(height[4],left=height[0])-height[1] = 2 - 1 = 1;
    w = 4 - 0 - 1 = 3;
    ans += 豆1,豆3,豆4;4进栈
  4. 结束 贴一个go的代码
func min (a int ,b int) int {
  if a > b {
    return b
  }
  return a
}
func solution(height []int) int{
  ans := 0
  st := make([]int,0)
  for index, h := range height {
    for len(st) > 0 && h > height[st[len(st)-1]] {
      mid := st[len(st)-1]
      st = st[:len(st)-1]
      if len(st) > 0 {
        left := st[len(st)-1]
        h := min(height[left],h) - height[mid]
        w := index - left - 1
        ans += h * w
      }
    }
    st = append(st,index)
  }
  return ans
}