题目描述
题目出自Leetcode 303. 区域和检索 - 数组不可变
给定一个整数数组nums ,求出数组从索引 i 到 j(i ≤ j) 范围内元素的总和,包含 i、j 两点。
实现 NumArray 类:
NumArray(int[] nums)使用数组nums初始化对象- 到
j(i ≤ j)范围内元素的总和,包含i、j两点(也就是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^50 <= i <= j < nums.length- 最多调用
10^4次sumRange方法
思路分析
这是一道简单题,入手我们可能第一个想到的解法就是在 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 > 0 和 sums(0, j) 的计算过程保持统一,我们在 sum[0] 存储了一个占位的 0 。
今天的每日打卡结束啦~ 好久没写题了,先找找感觉~