[路飞][LeetCode]327_区间和的个数

195 阅读2分钟

「这是我参与2022首次更文挑战的第37天,活动详情查看:2022首次更文挑战

看一百遍美女,美女也不一定是你的。但你刷一百遍算法,知识就是你的了~~

谁能九层台,不用累土起!

题目地址

题目

给你一个整数数组 nums 以及两个整数 lower 和 upper 。求数组中,值位于范围 [lower, upper] (包含 lower 和 upper)之内的 区间和的个数 。

区间和 S(i, j) 表示在 nums 中,位置从 i 到 j 的元素之和,包含 i 和 j (i ≤ j)。

示例 1:

输入: nums = [-2,5,-1], lower = -2, upper = 2
输出: 3
解释: 存在三个区间:[0,0][2,2][0,2] ,对应的区间和分别是:-2 、-1 、2 。

示例 2:

输入: nums = [0], lower = 0, upper = 0
输出: 1

提示:

  • 1 <= nums.length <= 105
  • -231 <= nums[i] <= 231 - 1
  • -105 <= lower <= upper <= 105
  • 题目数据保证答案是一个 32 位 的整数

解题思路

  • 我们对数组进行遍历,在遍历的同时我们从遍历到的项开始向后遍历
  • 如果两个遍历的索引值相同,重置区间和
  • 否则对区间和进行累加
  • 如果区间和在范围内,将计数+1

解题代码

var countRangeSum = function(nums, lower, upper) {
    let count= 0,sum = 0
    for(let i =0;i<nums.length;i++){
        for(let j=i;j<nums.length;j++){
            sum = j===i?nums[j]:sum+nums[j];
            if(sum >=lower&&sum<=upper){
                count++
            }
        }
    }
    return count
};

很遗憾,这个解法会报超时

优化解法

既然上面的方法不行,我们换一种方法,这次我们使用归并排序。

  • 先求出nums的前缀和数组
  • 在归并排序过程中进行满足条件的区间个数的统计
  • 递归回溯,每次得到两个升序数组
  • 固定一个数组的索引i,找另一个数组前缀和差在区间[lower, upper]的索引
  • 指针p1向右,找前缀和差>=lower第一个索引
  • 指针p2p1位置起向右,找前缀和差>upper第一个索引
var countRangeSum = function(nums, lower, upper) {
   const sums = [0]
   for(let i = 1; i <= nums.length; i++) {
       sums[i] = sums[i - 1] + nums[i - 1]
   }
   function merge_sort(l,r,f) {
        if(l>=r) return 0
        let m = l+r>>>1,i = l,p1 = m+1,p2,a
        let res = merge_sort(l,m) + merge_sort(m+1,r)
        while(i<=m){
            while(p1 <= r && sums[p1] - sums[i] <  lower) {
                p1++
            }
            p2 = p1
            while(p2 <= r && sums[p2] - sums[i] <= upper) {
                p2++
            }
            res += p2 - p1
            i++
        }
        if (f === 1) return res

        i = 0, p1 = l, p2 = m + 1, a = []
        while(p1 <= m || p2 <= r) {
             a[i++] = p2 > r || p1 <= m && sums[p1] < sums[p2] ? sums[p1++] : sums[p2++]
        }
           
        for(i = 0; i < a.length; i++) {
            sums[l + i] = a[i]
        }
        return res
       
   }

   return merge_sort(0,sums.length-1,1)
};

如有任何问题或建议,欢迎评论区留言讨论!