「力扣303」 区域和检索 - 数组不可变

162 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 12 天,点击查看活动详情

背景

今天笔者刷了一道力扣题 区域和检索 - 数组不可变,略有所得,分享给掘友🍺。

另外,笔者也开了一个新的 repo,沉淀自己刷题过程中的思考,欢迎大佬围观👏👏

题目

给定一个整数数组  nums,处理以下类型的多个查询:

  1. 计算索引 left 和 right (包含 left 和 right)之间的 nums 元素的  ,其中 left <= right

实现 NumArray 类:

  • NumArray(int[] nums) 使用数组 nums 初始化对象
  • int sumRange(int i, int j) 返回数组 nums 中索引 left 和 right 之间的元素的 总和 ,包含 left 和 right 两点(也就是 nums[left] + nums[left + 1] + ... + nums[right] )

示例:

class NumArray {
    ....
}

const numArray = new NumArray([-2, 0, 3, -5, 2, -1]);
numArray.sumRange(0, 2); // return 1 ((-2) + 0 + 3)
numArray.sumRange(2, 5); // return -1 (3 + (-5) + 2 + (-1)) 
numArray.sumRange(0, 5); // return -3 ((-2) + 0 + 3 + (-5) + 2 + (-1))

思路

最容易想到的是每次通过遍历累加 left...rightnums元素 来求结果,但是这样时间复杂度达到了 O(N),其实有更好的做法。

我们可以采用预处理数组的方式来做,根据 nums 来构建一个前缀和数组,每次查询只需要从前缀和数组 里查询 2 个点即可,这只需要 O(1) 的时间复杂度。

具体的做法

声明一个 nums 的前缀和数组 sumssums[i] 的值等于 nums[0]+nums[1]+...+nums[i],那么:

  1. i === 0 时, sums[0] = nums[0]
  2. i > 0 时, sum[i] = sum[i-1] + nums[i]

我们要计算的是 nums[left] + nums[left+1] + nums[left+2] + ... + nums[right] 的和,那么:

  1. left === 0 时,就是 nums[0]+nums[1]+...+nums[right],也就是 sums[right] 的值。
  2. left > 0 时,等同于:
(nums[0] + nums[1] + ... + nums[right]) - (nums[0] + nums[1] + ... + nums[left-1])

也就是:

sums[right] - sums[left-1]

于是,最终代码如下:

class NumArray {

  private _sums: number[];

  constructor(nums: number[]) {

    this._sums = Array(nums.length).fill(0);

    for (let i = 0, len = nums.length; i < len; i++) {
      this._sums[i] = i > 0 ? (this._sums[i - 1] + nums[i]) : nums[0];
    }
  }

  sumRange(left: number, right: number): number {
    return left > 0 ? (this._sums[right] - this._sums[left - 1]) : this._sums[right];
  }
}

手绘理解

下面是笔者思考过程手绘的一张图,可以帮助理解:

3.jpeg

总结

本文是笔者由一道力扣题引发的思考,涉及 预处理数组前缀和 等知识,「保持学习 主动思考 坚持输出」,我是前端涤生,希望这篇文章可以帮到您🍺🍺