給定一個整數數組 A
,找到 min(B)
的總和,其中 B
的範圍爲 A
的每一個(連續)子數組。數組
因爲答案可能很大,所以返回答案模 10^9 + 7
。spa
示例: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 <= A <= 30000
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 要快。