|
| 1 | +# Range Sum Query - Immutable |
| 2 | +Given an integer array nums, handle multiple queries of the following type: |
| 3 | + |
| 4 | +Calculate the sum of the elements of nums between indices left and right inclusive, where left <= right. |
| 5 | +Implement the NumArray class: |
| 6 | + |
| 7 | +NumArray(int[] nums) Initializes the object with the integer array nums. |
| 8 | +int sumRange(int left, int right) Returns the sum of the elements of nums between indices left and right inclusive (i.e., nums[left] + nums[left + 1] + ... + nums[right]). |
| 9 | + |
| 10 | +### Constraints: |
| 11 | +- 1 <= nums.length <= 10^4 |
| 12 | +- -10^5 <= nums[i] <= 10^5 |
| 13 | +- 0 <= left <= right < nums.length |
| 14 | +- At most 10^4 calls will be made to sumRange. |
| 15 | + |
| 16 | +### Examples |
| 17 | +```javascript |
| 18 | +Input: |
| 19 | +["NumArray", "sumRange", "sumRange", "sumRange"] |
| 20 | +[[[-2, 0, 3, -5, 2, -1]], [0, 2], [2, 5], [0, 5]] |
| 21 | + |
| 22 | +Output: |
| 23 | +[null, 1, -1, -3] |
| 24 | + |
| 25 | +Explanation: |
| 26 | +NumArray numArray = new NumArray([-2, 0, 3, -5, 2, -1]); |
| 27 | +numArray.sumRange(0, 2); // return 1 (-2 + 0 + 3 = 1) |
| 28 | +numArray.sumRange(2, 5); // return -1 (3 + -5 + 2 + -1 = -1) |
| 29 | +numArray.sumRange(0, 5); // return -3 (-2 + 0 + 3 + -5 + 2 + -1 = -3) |
| 30 | +``` |
| 31 | + |
| 32 | +## Approaches to Solve the Problem |
| 33 | +### Approach 1: Brute Force (Iterate Over Range) |
| 34 | +##### Intuition: |
| 35 | +The most straightforward approach is to iterate over the elements between indices left and right every time sumRange is called. This solution will work, but it may not be efficient if sumRange is called multiple times. |
| 36 | + |
| 37 | +Steps: |
| 38 | +1. Each time sumRange(left, right) is called, iterate over the elements from left to right and sum them. |
| 39 | +2. Return the sum after iterating over the range. |
| 40 | +##### Time Complexity: |
| 41 | +O(n) for each query, where n is the length of the range between left and right. |
| 42 | +##### Space Complexity: |
| 43 | +O(1), no extra space is used beyond a few variables for the sum. |
| 44 | +##### Python Code: |
| 45 | +```python |
| 46 | +class NumArray: |
| 47 | + |
| 48 | + def __init__(self, nums: List[int]): |
| 49 | + self.nums = nums # Store the input array |
| 50 | + |
| 51 | + def sumRange(self, left: int, right: int) -> int: |
| 52 | + # Calculate the sum by iterating over the range |
| 53 | + return sum(self.nums[left:right + 1]) |
| 54 | +``` |
| 55 | +### Approach 2: Prefix Sum (Preprocessing) |
| 56 | +##### Intuition: |
| 57 | +To optimize the sum range queries, we can use the concept of prefix sums. The idea is to preprocess the array and compute a cumulative sum array where each element at index i stores the sum of elements from the start of the array up to i. This allows us to compute any range sum in constant time. |
| 58 | + |
| 59 | +- Define prefix_sum[i] as the sum of elements nums[0] + nums[1] + ... + nums[i-1]. |
| 60 | +- To find the sum of the range [left, right], we can calculate: |
| 61 | +```python |
| 62 | +sumRange(left, right) = prefix_sum[right + 1] - prefix_sum[left] |
| 63 | +``` |
| 64 | + |
| 65 | +Steps: |
| 66 | + |
| 67 | +1. Precompute the cumulative sum array prefix_sum where each entry stores the sum of all elements before index i. |
| 68 | +2. Use this precomputed array to quickly answer range sum queries by subtracting two prefix sums. |
| 69 | + |
| 70 | +##### Why This Works: |
| 71 | +If a cycle exists, the fast pointer, moving twice as fast as the slow pointer, will "lap" the slow pointer and meet it again inside the cycle. |
| 72 | +##### Time Complexity: |
| 73 | +- O(n) for preprocessing the prefix sum array. |
| 74 | +- O(1) for each query, since we only perform subtraction of two values. |
| 75 | +##### Space Complexity: |
| 76 | +O(n), for storing the prefix sum array. |
| 77 | +##### Visualization: |
| 78 | +```rust |
| 79 | +For nums = [-2, 0, 3, -5, 2, -1], the prefix_sum array would be: |
| 80 | +prefix_sum = [0, -2, -2, 1, -4, -2, -3] |
| 81 | + |
| 82 | +To compute sumRange(0, 2), we do: |
| 83 | +sumRange(0, 2) = prefix_sum[3] - prefix_sum[0] = 1 - 0 = 1 |
| 84 | +``` |
| 85 | +##### Python Code: |
| 86 | +```python |
| 87 | +class NumArray: |
| 88 | + |
| 89 | + def __init__(self, nums: List[int]): |
| 90 | + # Create a prefix sum array |
| 91 | + self.prefix_sum = [0] * (len(nums) + 1) |
| 92 | + for i in range(1, len(self.prefix_sum)): |
| 93 | + self.prefix_sum[i] = self.prefix_sum[i - 1] + nums[i - 1] |
| 94 | + |
| 95 | + def sumRange(self, left: int, right: int) -> int: |
| 96 | + # Calculate the sum for the range using the prefix sum |
| 97 | + return self.prefix_sum[right + 1] - self.prefix_sum[left] |
| 98 | +``` |
| 99 | +## Summary |
| 100 | + |
| 101 | +| Approach | Time Complexity | Space Complexity | |
| 102 | +|-----------------------------------|-----------------|------------------| |
| 103 | +| Brute Force (Iterate Over Range) | O(n) per query | O(1) | |
| 104 | +| Prefix Sum (Preprocessing) | O(n) to preprocess, O(1) per query | O(n) for storing prefix sum | |
| 105 | + |
| 106 | +The Prefix Sum approach is the most optimal solution as it allows querying the sum of any range in constant time after an initial preprocessing step. |
0 commit comments