1. 程式人生 > >327. count-of-range-sum

327. count-of-range-sum

         這道題難度還是挺大的,基本上hard的題目都要費點腦子,根據一般的辦法,求和並暴力的複雜度是O(N^2),而題目中明確說O(N^2)是naive,所以,該題目的難點在於如何降低時間複雜度。

         題目大意:給定一組數和一個區間,求改組數中所有滿足該區間加和的子陣列的個數,就是從陣列中挑選一組連續的數,如果選出的數之和滿足條件,則視為一組有效數,如果不滿足條件,則為無效,求所有有效陣列的個數。

         思路是,假設建立一個sums陣列,sums[i]表示陣列中前i個數據之和,挑選從j到i之間的陣列,表示為sums[i]-sums[j],而該陣列要滿足lower <= sums[i]-sums[j] <= upper,sums[i]是我們當前遍歷到的最遠位置,sum[j]是已經遍歷過的位置,所以,已經存在於陣列中,而sum[i]是剛算出來的固定值,所以,只要在原來的sums陣列中找到滿足一定條件的sums[j],則j-i一定滿足條件。原式是lower <= sums[i]-sums[j] <= upper,則sums[i]-upper <= sums[j] <= sums[i]-lower。

          有了以上的分析思路就明確了,從0開始遍歷,當遍歷到陣列中前i個值之和時,只要判斷sums陣列中,前i 個值中有幾個滿足sums[i]-upper <= sums[j] <= sums[i]-lower(j<i)即可,將結果不斷累加,最終得到的就是所有滿足條件的情況個數。

以下是AC程式碼:

class Solution {
public:
    int countRangeSum(vector<int>& nums, int lower, int upper) {
        int res = 0;
        multiset<long long> numset;
        numset.insert(0);
        long long sum = 0;
        for (int i=0; i<nums.size(); ++i) {
            sum += nums[i];
            res += distance(numset.lower_bound(sum-upper), numset.upper_bound(sum-lower));
            numset.insert(sum);
        }
        return res;
    }
};