907. 子數組的最小值之和

給定一個整數數組 A,找到 min(B) 的總和,其中 B 的範圍爲 A 的每一個(連續)子數組。數組

因爲答案可能很大,所以返回答案模 10^9 + 7spa

 

示例:code

輸入:[3,1,2,4]
輸出: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。

 

提示:blog

  1. 1 <= A <= 30000
  2. 1 <= A[i] <= 30000

思路1:動態規劃,時間複雜度 n2索引

思路2:找技巧。找到每一個數A[i]被加的次數,從i往左數有l個數>=A[i],再從i往右數有r個數>A[i],這裏爲了不重複只能有一段取>=,這樣左邊有l+1種選擇,右邊有r+1種選擇,A[i]被加的次數就是(r+1)(l+1)。io

爲了實現上述思路,能夠直接來。可是有更便捷的方法,用棧。class

上述思路也能夠歸結爲,往左找到<=A[i]的數的索引k,往右找到<A[i]的數的索引j,這樣A[i]被加的次數就是(j-i)*(i-k)。技巧

假設棧頂元素爲A[i],當往右碰到j使得A[i] > A[j] 時就能夠將A[i]彈出,不然push A[j]。所以棧中A[i]的下一個元素必定知足A[k] <= A[i]。這正是咱們須要的邏輯。方法

最後的實現涉及到一些技巧,好比說先將A變爲 [0] + A + [0]。top

class Solution {
public:
    int sumSubarrayMins2(vector<int>& A) {
        int sum = 0;
        int sss = 1000000007;
        int n = A.size();
        if(n == 0) return 0;
        vector<int> res(n,INT_MAX);
        for(int k = 0;k<n;++k){
            for(int i = 0;i+k<n;++i){
                if(A[i+k] < res[i]){
                    res[i] = A[i+k];
                }
                sum += res[i];
                sum = sum > sss ? sum % sss : sum;
            }
        }
        return sum;
    }
    
    int sumSubarrayMins(vector<int>& A) {
        int res = 0;
        int sss = 1000000007;
        stack<int> s;
        A.insert(A.begin(),0);
        A.push_back(0);
        for(int i = 0;i<A.size();++i){
            while(!s.empty() && A[s.top()] > A[i]){
                int j = s.top();s.pop();
                int k = s.top();
                res += A[j]*(i-j)*(j-k);
            }
            s.push(i);
            res = res%sss;
        }
        return res;
    }
};

 噢,最後忘了說,取模。int 比 long long 要快。

相關文章
相關標籤/搜索