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
numsbetween indicesleftandrightinclusive 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 ofnumsbetween indicesleftandrightinclusive (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^50 <= left <= right < nums.length- At most
10^4calls 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
Qis the number of queries, andnis the length of input array - Space Complexity: O(n) where
nis 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.