代码之家  ›  专栏  ›  技术社区  ›  J. Doe

使用单调堆栈背后的直觉

  •  1
  • J. Doe  · 技术社区  · 5 年前

    LeetCode.com :

    给定一个整数数组A,求最小值(B)的和,其中B在A的每个(相邻)子数组上都有范围。由于答案可能很大,返回答案模10^9+7。

    输入
    输出 :17分
    :子数组为[3]、[1]、[2]、[4]、[3,1]、[1,2]、[2,4]、[3,1,2]、[1,2,4]、[3,1,2,4]。最小值为3,1,2,4,1,1,2,1,1,1。总数是17。

    A highly upvoted solution

    class Solution {
    public:
      int sumSubarrayMins(vector<int>& A) {
        stack<pair<int, int>> in_stk_p, in_stk_n;
        // left is for the distance to previous less element
        // right is for the distance to next less element
        vector<int> left(A.size()), right(A.size());
    
        //initialize
        for(int i = 0; i < A.size(); i++) left[i] =  i + 1;
        for(int i = 0; i < A.size(); i++) right[i] = A.size() - i;
    
        for(int i = 0; i < A.size(); i++){
          // for previous less
          while(!in_stk_p.empty() && in_stk_p.top().first > A[i]) in_stk_p.pop();
          left[i] = in_stk_p.empty()? i + 1: i - in_stk_p.top().second;
          in_stk_p.push({A[i],i});
    
          // for next less
          while(!in_stk_n.empty() && in_stk_n.top().first > A[i]){
            auto x = in_stk_n.top();in_stk_n.pop();
            right[x.second] = i - x.second;
          }
          in_stk_n.push({A[i], i});
        }
    
        int ans = 0, mod = 1e9 +7;
        for(int i = 0; i < A.size(); i++){
          ans = (ans + A[i]*left[i]*right[i])%mod;
        }
        return ans;
      }
    };
    

    我的问题是:使用单调递增的堆栈背后的直觉是什么?它如何帮助计算各种子阵中的最小值?

    0 回复  |  直到 5 年前
        1
  •  7
  •   Davis Herring    5 年前

    将数组可视化为一个线图,将(局部)最小值作为谷。每个值都与 从上一个较小值(如果有)之后延伸到下一个较小值(如果有)之前。(当考虑包含它的单例子数组时,即使是比它的邻居大的值也很重要) left right 追踪那个范围。

    阴影 相同的 每次(外部)循环迭代后的内容。