前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【一天一大 lee】区间和的个数 (难度:困难) - Day20201107

【一天一大 lee】区间和的个数 (难度:困难) - Day20201107

作者头像
前端小书童
发布2020-11-11 14:20:14
2750
发布2020-11-11 14:20:14
举报
文章被收录于专栏:前端小书童前端小书童

题目:

给定一个整数数组 nums,返回区间和在 [lower, upper] 之间的个数,包含 lower 和 upper。区间和 S(i, j) 表示在 nums 中,位置从 i 到 j 的元素之和,包含 i 和 j (i ≤ j)。

说明:最直观的算法复杂度是 O(n2) ,请在此基础上优化你的算法。

示例:

代码语言:javascript
复制
输入: nums = [-2,5,-1], lower = -2, upper = 2,
输出: 3 
解释: 3个区间分别是: [0,0], [2,2], [0,2],它们表示的和分别为: -2, -1, 2。

抛砖引玉

思路:

首先忽略题目中的复杂度说明,使用两层遍历枚举所有区间的,统计枚举的区间和满足要求的数量

抛砖引玉

代码语言:javascript
复制
/**
 * @param {number[]} nums
 * @param {number} lower
 * @param {number} upper
 * @return {number}
 */
var countRangeSum = function(nums, lower, upper) {
 let _result = 0
 for (let i = 0; i < nums.length; i++) {
  // 区间和
  let item = 0
  for (let j = i; j < nums.length; j++) {
   item = item + nums[j]
   if (item >= lower && item <= upper) _result++
  }
 }
 return _result
};

归并排序

归并排序是用于两个有序序列和并成一个有序序列的算分。

在本题中,考察的是数组子集的和是否在lower、upper之间,可先遍历nums求出其前缀和sum:0,nums[0],nums[0]+nums[1],nums[0]+nums[1]+nums[2]...

  • 枚举一sum的区间,用二分法切分成两个数组,两个数组分别取出一个值相减就形成了nums中一个区间
  • 对切分后的两个数组归并排序则枚举区间和时,指定一个指针就可以等到满足要求的边界区间
  • 归并排序,设两个子数组arr1、arr2(本题通过mid索引位置来划分两个子数组):
    • 先声明一个值长度arr1.length+arr2.length 的数组
    • 声明三个指针:一个为当前填充到结果位置的索引index,两位两个分别对应两个数组index1、index2
    • index1、index2位置上的数字,谁小谁先占据index位置,直到两个子数组遍历完
代码语言:javascript
复制

var countRangeSum = function (nums, lower, upper) {
  // 前缀元素和
  let sum = [0] 
  for (let  i = 1;i <= nums.length;i++) {
    sum[i] = sum[i - 1] + nums[i - 1]
  }

  function helper (left, right) {
   if (left === right) return 0
    let mid = Math.floor((left + right) / 2),
        // 先递归切分区间
        result = helper(left, mid) + helper(mid + 1, right);

    // 统计left到right之前满足条件的下标组合数量
    let index = left,
        l = mid + 1,
        r = mid + 1;
    while (index <= mid) {
      while (l <= right && sum[l] - sum[index] < lower) l++;
      while (r <= right && sum[r] - sum[index] <= upper) r++;
      result += (r - l);
      index++;
    }

    // 两个合并子树形成一个有序数组,保证后续切分的数组均为有序数组
    let sorted = Array(right - left + 1),
        p1 = left, 
        p2 = mid + 1,
        p = 0;
    while (p1 <= mid || p2 <= right) {
      if (p1 > mid) {
        sorted[p++] = sum[p2++];
      } else if (p2 > right) {
        sorted[p++] = sum[p1++];
      } else {
        if (sum[p1] < sum[p2]) {
          sorted[p++] = sum[p1++];
        } else {
          sorted[p++] = sum[p2++];
        }
      }
    }
    for (let i = 0; i < sorted.length; i++) {
      sum[left + i] = sorted[i];
    }
    return result;
  }

  return helper(0, sum.length - 1);
};
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-11-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端小书童 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 题目:
    • 示例:
    • 抛砖引玉
      • 归并排序
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档