【LeetCode】327. Count of Range Sum

題目:

Given an integer array nums, return the number of range sums that lie in [lower, upper] inclusive.    數組

Range sum S(i, j) is defined as the sum of the elements in nums between indices i and  j (ij), inclusive.post

Note:    spa

A naive algorithm of O(n2) is trivial. You MUST do better than that.指針

Example:    code

Given nums = [-2, 5, -1], lower = -2, upper = 2, Return 3. The three ranges are : [0, 0], [2, 2], [0, 2] and their respective sums are: -2, -1, 2.對象

提示:

這道題最直觀的一個想法就是枚舉出全部的子數組,而後檢查他們是否在要求的取值範圍內,這種方法的時間複雜度是O(n^2)的,顯然會超時。blog

看到這種題目最容易想到的是什麼呢?Two Pointers!對,可是在這道題上僅僅使用Two Pointers確定是不夠的,在Two Pointers的思想基礎上,融合歸併排序,就能找到一個比較好的解決方案。排序

這裏咱們的排序對象是前綴求和數組,在歸併排序的合併階段,咱們有左數組和右數組,且左和右數組都是排好序的,因此咱們能夠用i遍歷左數組,j,k兩個指針分別取在右數組搜索,使得:three

  • sums[j] - sums[i] < upper
  • sums[k] - sums[i] >= lower

那麼此時,咱們就找到了j-k個符合要求的子數組。element

因爲左右數組都是排好序的,因此當i遞增以後,j和k的位置不用從頭開始掃描。

最後還有一點須要注意的就是,爲了防止溢出,咱們的vector容納的是long long型元素。

代碼:

class Solution {
public:
    int countRangeSum(vector<int>& nums, int lower, int upper) {
        int n = nums.size();
        if (n <= 0) {
            return 0;
        }
        vector<long long> sums(n + 1, 0);
        for (int i = 0; i < n; ++i) {
            sums[i+1] = sums[i] + nums[i];
        }
        return merge(sums, 0, n, lower, upper);
    }
    
    int merge(vector<long long>& sums, int start, int end, int lower, int upper) {
        if (start >= end) {
            return 0;
        }
        int mid = start + (end - start) / 2;
        int count = merge(sums, start, mid, lower, upper) + merge(sums, mid + 1, end, lower, upper);
        vector<long long> tmp(end - start + 1, 0);
        int j = mid + 1, k = mid + 1, t = mid + 1, i = start, r = 0;
        for (; i <= mid; ++i, ++r) {
            while (j <= end && sums[j] - sums[i] <= upper) ++j;
            while (k <= end && sums[k] - sums[i] < lower) ++k;
            count += j - k;
            while (t <= end && sums[t] <= sums[i]) tmp[r++] = sums[t++]; 
            tmp[r] = sums[i];
        }
        for (int i = 0; i < r; ++i) {
            sums[start + i] = tmp[i];
        }
        return count;
    }
};
相關文章
相關標籤/搜索