壹 ❀ 引

本题来自LeetCode303. 区域和检索 - 数组不可变,属于一道简单题,不过题目期望的做法我也是看了题解才懂得,这里大致做个记录,题目描述如下:

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

实现 NumArray 类:

NumArray(int[] nums) 使用数组 nums 初始化对象

int sumRange(int i, int j) 返回数组 nums 从索引 i 到 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 <= 104

-105 <= nums[i] <= 105

0 <= i <= j < nums.length

最多调用 104 次 sumRange 方法

贰 ❀ 简单分析与暴力题解

题目其实不难理解,我们需要定义一个类NumArray,它接受一个数组nums作为初始化对象,然后调用此类的sumRange方法并传递两个参数i与j,并求出nums中索引i到索引j(i<=j且包含i与j)之间所有元素的和。

不用看官方给的例子,它给的输入看着有点莫名其妙,说直接点就是,假设我们有个数组[1,2,3,4]作为初始化参数,那么调用sumRange(1,3),得到的就是9,因为索引1是2,到索引3是4,中间还有个3,因此和为2+3+4

站在JS角度,这里我直接使用构造函数模拟这个类,因为暴力解法非常简单,这里直接贴代码:

/**
* @param {number[]} nums
*/
var NumArray = function(nums) {
this.nums = nums;
}; /**
* @param {number} i
* @param {number} j
* @return {number}
*/
NumArray.prototype.sumRange = function(i, j) {
let sum = 0;
while(i<=j){
sum+=this.nums[i++]
};
return sum;
};

在上述代码中,NumArray接受一个函数作为参数,之后调用sumRange时,我们也只需要通过遍历,将从i到j的所有数字累加,并最终返回结果即可。

叁 ❀ 前缀和

但事实上,如果你没了解过前缀和的概念,你可能完全不会想到此题的真正考点是希望你用前缀和来解决此问题。

站在暴力解法的角度,我们每调用一次sumRange其实都得从头开始把范围内的数字都重新加一半,这种行为是不具备缓存性质的。那么有没有什么办法,能够让我们在调用sumRange时不用做重复的工作,而是直接得到结果呢,这里就得介绍前缀和了。

也不卖关子,我们以一个数组[1,2,3,4,5]为例,所谓前缀和其实就是第i项保存了包含i以及i之前所有元素的和。

我们假设有个专门的数组用于存放前缀和,它的结果应该是这样:

元素:  1,2,3,4,5
前缀和:1,3,6,10,15

第一个前缀和为1,这是因为目前只有一个,因此为1。

第二个前缀和为3,这是因为2前面还有一个1,因此为1+2=3

第三个前缀和为6,这是因为1+2+3=6,但是我们之前已经计算过1+2了,因此我们可以用上次的前缀和加上当前元素就好了,简化为3+3

以此类推,假设前缀和的数组为preSum,那么:

preSum[i] = preSum[i-1] + nums[i]

我们期望上面的公式能适用于数组遍历的整个过程,但很明显当索引为0时,此时只有一个元素1,都不存在preSum[i-1],怎么办呢?聪明的前辈们想到了一个机智的做法,nums不是长度为5吗,那我的preSum初始化时长度就在nums长度基础上加个1也就是6,并将preSum[0]直接设置为0,也就是:

let preSum = new Array(nums.length);
preSum[0] = 0;

直接让pre多出一个,并将其设置为0,方便后续每一次的前缀和计算,简直妙哉。因此我们可以在第一次遍历数组时,就得到对应的前缀和数组,上代码:

var NumArray = function (nums) {
// 我需要一个length+1的数组,用于保存前缀和
const preSum = new Array(nums.length + 1);
// 为了让前缀和的公式适用于数组每一位计算,所以将0位的值设置为0
preSum[0] = 0;
// 虽然公式是pre[i] = pre[i-1] + nums[i],但是索引是从0开始的,因此preSum的第一位应该是i+1
for (let i = 0; i < nums.length; i++) {
preSum[i + 1] = preSum[i] + nums[i];
}
this.preSum = preSum;
};

OK,那么到这里我们得到了一个前缀和数组,但题目的目的是调用sumRange(i,j)时能得到次区间的和,怎么办呢?

还是举个简单的例子,以数组[1,2,3,4,5]为例,求假设i为1,j为3,求i-j区间的和。

首先0-3的和为1+2+3+4,而1-3的和为2+3+4,因此可以得知,1-3的和可以是0-3的和减去一个1,也就是减去一个preSum[i-1]

但由于我们在声明preSum时长度加了个1,因此从要跟nums的下标对应的话,我们在计算时,公式应该为:

sumRange(i, j) = preSum[j + 1] - preSum[i]

还是上面的数组例子,假设要求1-3的区间和,很明显应该是10-1=9,说到底就是初始值0的问题,要让j加一位,这样计算才是正确的。

元素:  1,2,3,4,5
前缀和:0,1,3,6,10,15

综合上述代码,可以以前缀和的思路得到最终代码:

var NumArray = function (nums) {
// 我需要一个length+1的数组,用于保存前缀和
const preSum = new Array(nums.length + 1);
// 为了让前缀和的公式适用于数组每一位计算,所以将0位的值设置为0
preSum[0] = 0;
// 虽然公式是pre[i] = pre[i-1] + nums[i],但是索引是从0开始的,因此preSum的第一位应该是i+1
for (let i = 0; i < nums.length; i++) {
preSum[i + 1] = preSum[i] + nums[i];
}
this.preSum = preSum;
}; NumArray.prototype.sumRange = function (i, j) {
return this.preSum[j + 1] - this.preSum[i];
};

这样每次查询区间和时,我们都能利用之前遍历缓存的前缀和高效得到最终结果,大功告成,本文结束。

JS LeetCode 303. 区域和检索 - 数组不可变,一维数组的前缀和的更多相关文章

  1. Java实现 LeetCode 303 区域和检索 - 数组不可变

    303. 区域和检索 - 数组不可变 给定一个整数数组 nums,求出数组从索引 i 到 j (i ≤ j) 范围内元素的总和,包含 i, j 两点. 示例: 给定 nums = [-2, 0, 3, ...

  2. [Leetcode]303.区域和检索&&304.二维区域和检索

    题目 1.区域和检索: 简单题,前缀和方法 乍一看就觉得应该用前缀和来做,一个数组多次查询. 实现方法: 新建一个private数组prefix_sum[i],用来存储nums前i个数组的和, 需要找 ...

  3. LeetCode:区域和检索【303】

    LeetCode:区域和检索[303] 题目描述 给定一个整数数组  nums,求出数组从索引 i 到 j  (i ≤ j) 范围内元素的总和,包含 i,  j 两点. 示例: 给定 nums = [ ...

  4. Leetcode 304.二维区域和检索-矩阵不可变

    二维区域和检索 - 矩阵不可变 给定一个二维矩阵,计算其子矩形范围内元素的总和,该子矩阵的左上角为 (row1, col1) ,右下角为 (row2, col2). 上图子矩阵左上角 (row1, c ...

  5. Java实现 LeetCode 304 二维区域和检索 - 矩阵不可变

    304. 二维区域和检索 - 矩阵不可变 给定一个二维矩阵,计算其子矩形范围内元素的总和,该子矩阵的左上角为 (row1, col1) ,右下角为 (row2, col2). Range Sum Qu ...

  6. [Swift]多维数组的表示和存储:N维数组映射到一维数组(一一对应)!

    数组:有序的元素序列. 若将有限个类型相同的变量的集合命名,那么这个名称为数组名.组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量.用于区分数组的各个元素的数字编号称为下标.数组 ...

  7. PHP开发小技巧③—实现多维数组转化为一维数组

    在平常的项目开发中我们多会用到让多维数组转化为一维数组的情况,但是很多Programmer不会将其进行转化,也有些没有想到很好的算法然后经过乱起八糟的运算方式将其勉强转化好,但是所写的程序代码冗余非常 ...

  8. 二维数组转化为一维数组 contact 与apply 的结合

    将多维数组(尤其是二维数组)转化为一维数组是业务开发中的常用逻辑,除了使用朴素的循环转换以外,我们还可以利用Javascript的语言特性实现更为简洁优雅的转换.本文将从朴素的循环转换开始,逐一介绍三 ...

  9. Java实现 LeetCode 307 区域和检索 - 数组可修改

    307. 区域和检索 - 数组可修改 给定一个整数数组 nums,求出数组从索引 i 到 j (i ≤ j) 范围内元素的总和,包含 i, j 两点. update(i, val) 函数可以通过将下标 ...

  10. [C++]指针和指向数组的指针[一维数组与指针]

     1.一维数组与指针      形如:int型 数组 a[10]                1)&a[0]  地址常量;地址类型:int *型   ; 存储数组a的首地址          ...

随机推荐

  1. node pressure and pod eviction

    0. overview There are too many guides about node pressure and pod eviction, most of them are specifi ...

  2. Asp.Net Core造轮之旅:逐步构建自己的开发框架-目录

    本系列适用于已有一定.NET开发基础,学习asp.net core人士. 基础篇 asp.net core之Startup asp.net core之依赖注入 asp.net core之中间件 asp ...

  3. Verdi基础-01

    Verdi使用目标 生成fsdb波形 查看fsdb波形 追踪RTL代码 目录 Verdi历史 生成fsdb波形 三个变量&&三个命令 变量PATH LD_LIBRARY_PATH so ...

  4. 【TouchGFX】Callback

    回调函数模板定义 单参数回调函数模板 实现回调函数接口: 实现合法性检查接口: 实现执行接口: 按键触发回调实现 定义回调数据结构对象 使用回调数据结构构造函数 执行接口实现 整个切换机制的管理主体对 ...

  5. phpcms: Warning: "continue" targeting switch is equivalent to "break" 解决方案

    Warning: "continue" targeting switch is equivalent to "break". Did you mean to u ...

  6. 持续集成指南:Gitlab CI/CD 自动部署前端项目

    前言 之前陆续写了 Gitlab 的安装使用还有 Gitlab CI/CD 的配置使用,已经把 AspNetCore 的后端项目都做了持续集成了,尝到甜头之后,现在前端的项目也要加入自动化部署,所以经 ...

  7. [转帖]充分利用 Oracle SQL监控

    https://zhuanlan.zhihu.com/p/397834311 经常被问到查看执行计划的最佳工具是什么,对我来说,答案总是SQL Monitor(包含在 Oracle Tuning Pa ...

  8. [转帖]TIDB_HOT_REGIONS

    https://docs.pingcap.com/zh/tidb/stable/information-schema-tidb-hot-regions TIDB_HOT_REGIONS 表提供了关于当 ...

  9. [转帖]iozone - 性能压力测试工具

    <存储工具系列文章>主要介绍存储相关的测试和调试工具,包括不限于dd.fio.vdbench.iozone.iometer.cosbench等性能负载工具,及strace等调试工具. 1 ...

  10. Python学习之八_调用Outlook发送邮件以及调用远程windows上面的python

    Python学习之八_调用Outlook发送邮件以及调用远程windows上面的python 摘要 之前只有一个需求是发送加密邮件. 之前一直是使用linux进行发送.但是总是无法发送加密邮件. 最近 ...