壹 ❀ 引

本题来自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. 在Python中使用Process创建子进程遇到的问题

    假如使用Process创建子进程,那么在最后的函数调用时需要加上if __name__ == "__main__":语句,否则会报错. 未使用该语句 代码示例 from multi ...

  2. kafka Linux环境搭建安装及命令创建队列生产消费消息

    本文为博主原创,未经允许不得转载: 1. 安装JDK 由于Kafka是用Scala语言开发的,运行在JVM上,因此在安装Kafka之前需要先安装JDK. yum install java‐1.8.0‐ ...

  3. Visual Studio实用的搜索、查找、替换技巧

    前言 对于.NET开发者而言Visual Studio是我们日常工作中比较常用的开发工具,掌握一些Visual Studio实用的搜索.查找.替换技巧可以帮助我们大大提高工作效率从而避免996. Vi ...

  4. 例2.9 建立一个带头结点的线性链表,用以存放输人的二进制数,链表中每个结点的data域存放一个二进制位。并在此链表上实现对二进制数加1的运算。

    1.题目 例2.9建立一个带头结点的线性链表,用以存放输人的二进制数,链表中每个结点的data域存放一个二进制位.并在此链表上实现对二进制数加1的运算. 2.算法分析 3.代码 /* 二进制加1 */ ...

  5. 软考下午科目——第三章——UML分析与设计

    UML分析与设计 大纲要求: 学会面向对象的分析与设计,掌握UML描述方法 UML基础知识 面向对象的分析与设计 面向对象方法是一种运用对象.类.继承.封装.聚合.关联.消息.多态性等概念来构造系统的 ...

  6. C++开发PHP扩展

    前端时间用C开发PHP扩展,用C实现字符串和简单的cache不友好,因而有了用C++开发的想法. 相关环境初始化配置准备 1.用php源码提供的脚手架生成扩展名 php ext/ext_skel.ph ...

  7. [转帖]TLS1.3 正式版发布 — 特性与开启方式科普

    https://cloud.tencent.com/developer/article/1376033 互联网工程指导委员会(IETF)释出了传输层安全性协议的最新版本 TLS 1.3.TLS 被广泛 ...

  8. [转帖]十分钟掌握 Vim 编辑器核心功能

    https://juejin.cn/post/6929248764746006535 前言 相信不论是前端还是后台多多少少都需要上到服务器上做一些操作,改改配置文件等,大多数 Linux 服务器默认都 ...

  9. Oracledb_exporter 获取表大小信息的简单方法

    Oracledb_exporter 获取表大小信息的简单方法 背景 用我儿子的现状作为背景: 我爱学习, 学习让我妈快乐. 下载exporter exporter 可以在github上面下载最新版本是 ...

  10. Python 潮流周刊第 29 期(摘要)

    本周刊由 Python猫 出品,精心筛选国内外的 250+ 信息源,为你挑选最值得分享的文章.教程.开源项目.软件工具.播客和视频.热门话题等内容.愿景:帮助所有读者精进 Python 技术,并增长职 ...