Range Sum Query - Immutable
Problem
Given an integer array nums, handle multiple queries of the following type: Calculate the sum of the elements of nums between indices left and right inclusive where left <= right.
Implement the NumArray class:
NumArray(int[] nums)- Initializes the object with the integer arraynumsint sumRange(int left, int right)- Returns the sum of the elements ofnumsbetween indicesleftandrightinclusive (i.e.,nums[left] + nums[left + 1] + ... + nums[right])
Constraints:
1 <= nums.length <= 10⁴-10⁵ <= nums[i] <= 10⁵0 <= left <= right < nums.length- At most
10⁴calls will be made tosumRange
Examples
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
Solution
This problem is a classic application of the prefix sum technique. Since the array is immutable and sumRange will be called multiple times, we can precompute prefix sums to answer each query in constant time.
Algorithm:
-
Precompute prefix sums: Create an array
preSumwherepreSum[i]represents the sum of all elements from index0toi-1in the original arraypreSum[0] = 0(no elements)preSum[i] = preSum[i-1] + nums[i-1]fori >= 1
-
Answer queries in O(1): To find the sum from
lefttoright, use the formula:sumRange(left, right) = preSum[right + 1] - preSum[left]
Why this works:
preSum[right + 1]contains the sum from index0torightpreSum[left]contains the sum from index0toleft - 1- Subtracting these gives us the sum from
lefttoright
Example visualization:
nums = [-2, 0, 3, -5, 2, -1]
preSum = [0, -2, -2, 1, -4, -2, -3]
sumRange(2, 5) = preSum[6] - preSum[2] = -3 - (-2) = -1
Time Complexity:
- Constructor: O(n) - to build the prefix sum array
- sumRange: O(1) - constant time lookup and subtraction
Space Complexity: O(n) - to store the prefix sum array
class NumArray {
private preSum: number[]
constructor(nums: number[]) {
this.preSum = new Array(nums.length + 1).fill(0)
for (let i = 0; i < nums.length; i++) {
this.preSum[i + 1] = this.preSum[i] + nums[i]
}
}
sumRange(left: number, right: number): number {
return this.preSum[right + 1] - this.preSum[left]
}
}
/**
* Your NumArray object will be instantiated and called as such:
* var obj = new NumArray(nums)
* var param_1 = obj.sumRange(left,right)
*/