leetcode.303.Range Sum Query

来源:互联网 发布:仿模板天空 源码 编辑:程序博客网 时间:2024/06/05 21:09

Description

Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive.
Example:

Given nums = [-2, 0, 3, -5, 2, -1]sumRange(0, 2) -> 1sumRange(2, 5) -> -1sumRange(0, 5) -> -3

Note:
You may assume that the array does not change.
There are many calls to sumRange function.

sln1

遇到这个问题首先第一个想法是构造函数的时候直接把整个vector存下来,然后在查询i到j直接的和的时候一个循环返回结果,但是如果查询是十分频繁且重复的,那么这样做的效率就十分低。那么我们就想如何在构造函数的时候计算出每个i到j之间的和,使得查询效率可以最好到O(1)。
那么在构造函数中,我们可以用一个三层循环完成这项工作,如下:

for (int i = 0; i < nums.size(); i++) {    for (int j = 0; j < nums.size(); j++) {        for (int k = i; k <= j; k++) {            sum[i][j] += nums[k];        }    }}

但是当输入的数组很大的时候,显然O(n^3)的复杂度是不被接受的。那么我们可以用另外一种方法来构造这个和矩阵。思路如下:

i == j:     sum[i][j] = nums[j]j - i == 1:    sum[i][j] = sum[i][j - 1] + sum[i + 1][j]j - i > 1:    sum[i][j] = sum[i][j - 1] + sum[j - 1][j] - nums[j - 1]

这样的话只要通过两个循环就可以完成sum矩阵的构造,然而实现了以上算法后提交得到的结果还是timelimit。继续思考没有结果,于是求助discussion。

sln2

discussion中有一个代码简介思路简单然而却能以O(n)的复杂度完成构造函数,并以O(1)的复杂度完成查询,个人感觉很机智:
要计算整个数组中i到j的和是比较麻烦的,但是如果要计算0到k的和只要一次循环就能完成。那么假设我们现在已经有一个accu,且accu[k]为nums数组从0到k的累加。那么我们要查询nums数组i到j的累加时,只需要accu[j + 1] - accu[i]即可。实现如下:

class NumArray {public:    NumArray(vector<int> &nums) {        accu.push_back(0);        for (int num : nums)            accu.push_back(accu.back() + num);    }    int sumRange(int i, int j) {        return accu[j + 1] - accu[i];    }private:    vector<int> accu;};