Range Query Sum Immutable
Range Query Sum Immutable:
Given an integer array nums
, handle multiple queries of the following type:
- Calculate the sum of the elements of
nums
between indicesleft
andright
inclusive whereleft <= right
.
Implement the NumArray
class:
NumArray(int[] nums)
Initializes the object with the integer arraynums
.int sumRange(int left, int right)
Returns the sum of the elements ofnums
between indicesleft
andright
inclusive (i.e.nums[left] + nums[left + 1] + ... + nums[right]
).
Example 1:
Input
["NumArray", "sumRange", "sumRange", "sumRange"]
[[[-2, 0, 3, -5, 2, -1]], [0, 2], [2, 5], [0, 5]]
Output
[null, 1, -1, -3]
Explanation
NumArray numArray = new NumArray([-2, 0, 3, -5, 2, -1]);
numArray.sumRange(0, 2); // return (-2) + 0 + 3 = 1
numArray.sumRange(2, 5); // return 3 + (-5) + 2 + (-1) = -1
numArray.sumRange(0, 5); // return (-2) + 0 + 3 + (-5) + 2 + (-1) = -3
Constraints:
1 <= nums.length <= 10^4
-10^5 <= nums[i] <= 10^5
0 <= left <= right < nums.length
- At most
10^4
calls will be made tosumRange
.
Try this Problem on your own or check similar problems:
Solution:
- Java
- JavaScript
- Python
- C++
class NumArray {
private List<Integer> prefixSum = new ArrayList<>();
public NumArray(int[] nums) {
int currentSum = 0;
for(int i = 0; i < nums.length; ++i){
prefixSum.add(currentSum);
currentSum += nums[i];
}
prefixSum.add(currentSum);
}
public int sumRange(int left, int right) {
return prefixSum.get(right + 1) - prefixSum.get(left);
}
}
/**
* @param {number[]} nums
*/
var NumArray = function (nums) {
this.prefixSum = [];
let currentSum = 0;
for (let i = 0; i < nums.length; ++i) {
currentSum += nums[i];
this.prefixSum.push(currentSum);
}
};
/**
* @param {number} left
* @param {number} right
* @return {number}
*/
NumArray.prototype.sumRange = function (left, right) {
return this.prefixSum[right] - (left > 0 ? this.prefixSum[left - 1] : 0);
};
/**
* Your NumArray object will be instantiated and called as such:
* var obj = new NumArray(nums)
* var param_1 = obj.sumRange(left,right)
*/
class NumArray:
def __init__(self, nums: List[int]):
self.prefixSum = []
currentSum = 0
for i in range(len(nums)):
self.prefixSum.append(currentSum)
currentSum += nums[i]
self.prefixSum.append(currentSum)
def sumRange(self, left: int, right: int) -> int:
return self.prefixSum[right + 1] - self.prefixSum[left]
# Your NumArray object will be instantiated and called as such:
# obj = NumArray(nums)
# param_1 = obj.sumRange(left,right)
class NumArray {
private:
vector<int> prefixSum;
public:
NumArray(vector<int>& nums) {
int currentSum = 0;
for (int i = 0; i < nums.size(); ++i) {
prefixSum.push_back(currentSum);
currentSum += nums[i];
}
prefixSum.push_back(currentSum);
}
int sumRange(int left, int right) {
return prefixSum[right + 1] - prefixSum[left];
}
};
/**
* Your NumArray object will be instantiated and called as such:
* NumArray* obj = new NumArray(nums);
* int param_1 = obj->sumRange(left,right);
*/
Time/Space Complexity:
- Time Complexity: O(Q + n) where
Q
is the number of queries, andn
is the length of input array - Space Complexity: O(n) where
n
is the length of array
Explanation:
So in our solution we have query in O(1)
and initialization O(n). It would be trivial during the query to loop over to the left index and right index and sum the numbers between,but that would leave us to O(n)
time complexity on query which is not practical since we have high asymmetry between read and writes (in other words we read way more often than we write) so we have to optimize for querying. How do we do that? We can introduce prefixSum
on class initialization, a prefix sum is basically the sum of all previous numbers for each of the indices in input array (in other words for element at index 2 the prefixSum will be the sum of first two number arr[0]
and arr[1]
). How does this help us calculate the sum between two indices? Well if substract prefixSum from the left index and prefixSum from right+1
what do we get? We get the sum of all numbers between those two indices.