Leetcode303 区域和检索 | 刷题打卡

238 阅读1分钟

题目描述

题目出自Leetcode 303. 区域和检索 - 数组不可变

给定一个整数数组nums ,求出数组从索引 ij(i ≤ j) 范围内元素的总和,包含 ij 两点。

实现 NumArray 类:

  • NumArray(int[] nums) 使用数组 nums 初始化对象
  • j(i ≤ j)范围内元素的总和,包含 ij 两点(也就是 sum(nums[i], nums[i + 1], ... , nums[j])

示例:

输入:
["NumArray", "sumRange", "sumRange", "sumRange"]
[[[-2, 0, 3, -5, 2, -1]], [0, 2], [2, 5], [0, 5]]
输出:
[null, 1, -1, -3]

解释:
NumArray 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))

提示:

  • 0 <= nums.length <= 10^4
  • -10^5 <= nums[i] <= 10^5
  • 0 <= i <= j < nums.length
  • 最多调用 10^4sumRange 方法

思路分析

这是一道简单题,入手我们可能第一个想到的解法就是在 sumRange 遍历循环计算。但是再仔细看看提示?好家伙!如果我们要调用了 10^4 次方法,意味我们要重复计算很多值。

因此,我们想到了利用前缀和来优化(缓存)这个过程 —— 再初始化的时候,遍历一遍统计前缀和。

进一步的优化呢?其实,我们还可以将计算前缀和的过程推迟到需要的时候再计算。

题目解答

/**
 * @param {number[]} nums
 */
var NumArray = function (nums) {
    let sums = [0];
    nums.forEach((num, i) => {
        sums.push(sums[i] + nums[i]);
    })
    this.sums = sums;
};

/** 
 * @param {number} i 
 * @param {number} j
 * @return {number}
 */
NumArray.prototype.sumRange = function (i, j) {
    return this.sums[j + 1] - this.sums[i];
};
/**
 * @param {number[]} nums
 */
var NumArray = function (nums) {
    this.sums = [0];
    this.nums = nums;
};

/** 
 * @param {number} i 
 * @param {number} j
 * @return {number}
 */
NumArray.prototype.sumRange = function (i, j) {
    let k = this.sums.length - 1;
    while (k <= j) {
        this.sums.push(this.sums[k] + this.nums[k]);
        k++;
    }
    return this.sums[j + 1] - this.sums[i];
};

总结

这道题目的解答主要用到前缀和的思想。同时,我们注意到这里还有一个小技巧,为了保证 sums(i, j), i > 0sums(0, j) 的计算过程保持统一,我们在 sum[0] 存储了一个占位的 0 。

今天的每日打卡结束啦~ 好久没写题了,先找找感觉~