Range Sum Query - Immutable — Solution in Python, Java & C++
Range Sum Query - Immutable solution explained: step-by-step approach, complexity and code in Python, Java, C++ and JavaScript. An easy problem.
Range Sum Query - Immutable is an easy coding problem on arrays and prefix sum, asked in Amazon, Google and Meta interviews.
- Difficulty: Easy
- Topics: Arrays, Prefix Sum
- Asked at: Amazon, Google, Meta
- Time limit: 2 s
- Memory limit: 256 MB
- Languages: JavaScript, TypeScript, Python, Java, C++, C, C#, Go, Kotlin, Swift, Rust, PHP and Ruby
Problem statement
Given an integer array nums, answer many queries of the form: what is the sum of the elements of nums between indices left and right, inclusive? The array never changes.
Write the class NumArray:
NumArray(int[] nums)initialises the object with the arraynums.int sumRange(int left, int right)returnsnums[left] + nums[left + 1] + … + nums[right].
The judge calls the constructor and then sumRange with the arguments listed in the second input line; the expected output holds each call's result, null for the constructor.
Example 1
Input: ["NumArray","sumRange","sumRange","sumRange"]
[[[-3,5,0,2,-6,4]],[0,2],[2,5],[0,5]]
Output: [null,2,0,2]
Explanation: -3 + 5 + 0 = 2; 0 + 2 + (-6) + 4 = 0; the whole array sums to 2.
Example 2
Input: ["NumArray","sumRange","sumRange"]
[[[7]],[0,0],[0,0]]
Output: [null,7,7]
Explanation: A one-element array answers every query with that element.
Constraints
1 <= nums.length <= 10^4-10^5 <= nums[i] <= 10^50 <= left <= right < nums.lengthAt most 10^4 calls are made to sumRange
Hints for Range Sum Query - Immutable
Hint 1
Summing the range on every query costs O(n) per call — up to 10^8 work. Precompute something once instead.
Hint 2
If you knew the sum of every prefix
nums[0..i-1], how would you get the sum ofnums[left..right]?Hint 3
Store
prefix[i] = nums[0] + … + nums[i-1](withprefix[0] = 0). ThensumRange(left, right) = prefix[right + 1] - prefix[left].
How to solve Range Sum Query - Immutable
Precompute prefix sums once in the constructor; every range sum is then the difference of two prefix sums, answered in O(1).
Approach
- In the constructor build
prefixof lengthn + 1:prefix[0] = 0andprefix[i + 1] = prefix[i] + nums[i]. sumRange(left, right)returnsprefix[right + 1] - prefix[left].
Why it works
prefix[right + 1] is the sum of nums[0..right] and prefix[left] the sum of nums[0..left-1]; their difference leaves exactly nums[left..right]. The extra leading zero makes left = 0 need no special case.
Complexity
- Time —
O(n) to build, O(1) per query - Space —
O(n)
Pitfalls
- Off-by-one: with the leading zero the right end is
prefix[right + 1], notprefix[right]. - The prefix sums stay within ±10^9 under the constraints, so 32-bit integers are enough.
Reference solution
Python
from typing import List
class NumArray:
def __init__(self, nums: List[int]):
self.prefix = [0]
for x in nums:
self.prefix.append(self.prefix[-1] + x)
def sumRange(self, left: int, right: int) -> int:
return self.prefix[right + 1] - self.prefix[left]Java
class NumArray {
private int[] prefix;
public NumArray(int[] nums) {
prefix = new int[nums.length + 1];
for (int i = 0; i < nums.length; i++) prefix[i + 1] = prefix[i] + nums[i];
}
public int sumRange(int left, int right) {
return prefix[right + 1] - prefix[left];
}
}C++
class NumArray {
vector<int> prefix;
public:
NumArray(vector<int>& nums) : prefix(nums.size() + 1, 0) {
for (size_t i = 0; i < nums.size(); i++) prefix[i + 1] = prefix[i] + nums[i];
}
int sumRange(int left, int right) {
return prefix[right + 1] - prefix[left];
}
};JavaScript
var NumArray = function(nums) {
this.prefix = [0];
for (var i = 0; i < nums.length; i++) this.prefix.push(this.prefix[i] + nums[i]);
};
NumArray.prototype.sumRange = function(left, right) {
return this.prefix[right + 1] - this.prefix[left];
};Also on the editorial tab: C, C#, Go, Kotlin, PHP, Ruby, Rust, Swift, TypeScript.
All 1199 arrays problems · the whole catalogue
Learn the technique: Arrays · Prefix Sum