1. 程式人生 > >907. 子陣列的最小值之和

907. 子陣列的最小值之和

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

由於答案可能很大,因此返回答案模 10^9 + 7

示例:

輸入:[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。

提示:

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

解答如下:(這題對問題進行復雜度優化,是解決問題的關鍵,一個是統計相同數值的個數,進行了一次優化,其次是計算針對一個數值為尾的N個子陣列的最小值的和,利用上次結果,進行第二次優化;否則將執行超時)

class Solution {
public:
    int sumSubarrayMins(vector<int>& A) {
        int size=A.size();
        //dp[i]為以當前位置為尾,以前面某個數字為首,其最小值為i的的個數,
        //這裡用map,利用紅黑樹的特性,可以進行log(2,n)的快速查詢
        map<int,long long> dp;
        long long result=0;//這裡是總結果
        long long temp=0;//這裡是針對某個數值A[n],其前邊A[n];A[n-1],A[n];...;A[0]...A[n]的最小值的和
        for(int i=0;i<size;i++){
            //若不存在當前數值,則以該數值本身構成的子陣列個數為1
            if(dp.find(A[i])==dp.end()){
                dp[A[i]]=1;
            }else{
                //若存在,則以該數字為最小值的dp[A[i]]+1
                dp[A[i]]+=1;
            }
            //新增一個數,其本身作為子陣列,需要計入當前數值temp中
            temp+=A[i];
            //這裡利用upper_bound(),用log(2,n)的時間複雜度查詢到比他大元素迭代器
            for(map<int,long long>::iterator iter= dp.upper_bound(A[i]);iter!=dp.end();){
                    //因為A[i]作為尾,所以比他大的都要降級,即減少(iter->first-A[i])*iter->second
                    temp-=(iter->first-A[i])*iter->second;
                    dp[A[i]]+=iter->second;//由於減少到A[i],所以需要將數量併入dp[A[i]]
                    dp.erase(iter++);//因為降級,所以不存在了。這裡iter++的用法十分巧妙
                    //答主用dp.erase(iter);
                    //然後用iter--(因為後面的iter++在for迴圈中); 再iter++,居然出現異常,無法刪除最後一個元素
                    //糾錯卡了半天
                }
            result=(temp+result)%(1000000000 + 7);
        }
        return result;
    }
};