zoukankan      html  css  js  c++  java
  • 【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.

    Note:    

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

    Example:    

    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)的,显然会超时。

    看到这种题目最容易想到的是什么呢?Two Pointers!对,但是在这道题上仅仅使用Two Pointers肯定是不够的,在Two Pointers的思想基础上,融合归并排序,就能找到一个比较好的解决方案。

    这里我们的排序对象是前缀求和数组,在归并排序的合并阶段,我们有左数组和右数组,且左和右数组都是排好序的,所以我们可以用i遍历左数组,j,k两个指针分别取在右数组搜索,使得:

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

    那么此时,我们就找到了j-k个符合要求的子数组。

    由于左右数组都是排好序的,所以当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;
        }
    };
  • 相关阅读:
    xpath获取a标签下文本
    Python学习笔记Day26
    DNS原理
    命令实战解析
    linux系统ext文件系统知识
    磁盘分区重点知识
    机械磁盘读写磁盘数据的原理
    linux用户管理
    linux命令讲解
    linux系统定时任务
  • 原文地址:https://www.cnblogs.com/jdneo/p/5388501.html
Copyright © 2011-2022 走看看