Skip to content

Commit 3b3b2ef

Browse files
committed
PrefixSum
1 parent abef828 commit 3b3b2ef

1 file changed

Lines changed: 175 additions & 0 deletions

File tree

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
# Prefix Sum Mastery Guide
2+
Efficient technique to answer range sum queries in `O(1)` time after preprocessing.
3+
4+
---
5+
6+
## Motivation: The Brute Force Bottleneck
7+
8+
### The Problem
9+
Given an array of integers, answer multiple queries of the form:
10+
> What is the sum of elements from index **L** to **R** (inclusive)?
11+
12+
### Why Brute Force Fails
13+
- **Process:** Summing elements for each query requires a loop from `L` to `R`.
14+
- **Complexity:** `O(N)` per query.
15+
- **Scale:** For `Q` queries, the total time is `O(N × Q)`. If `N` and `Q` are both `10^5`, you face `10^10` operations—too slow for standard execution time limits (usually `10^8` ops/sec).
16+
17+
---
18+
19+
## Key Idea & Intuition
20+
21+
### The Core Concept
22+
Instead of recomputing sums repeatedly, **store cumulative sums once**.
23+
24+
If you know:
25+
1. The total sum from index `0 → R`
26+
2. The total sum from index `0 → L-1`
27+
28+
Then the middle section (`L` to `R`) is simply the difference:
29+
> **Range Sum (L, R) = Prefix[R] − Prefix[L − 1]**
30+
31+
32+
33+
### Mental Model
34+
Think of prefix sum as a **"running total"** or **"accumulation"** up to a specific point.
35+
- ❌ No loops per query
36+
- ✅ Precompute once (`O(N)`)
37+
- ✅ Reuse previous work (`O(1)`)
38+
39+
---
40+
41+
## Algorithm Step-by-Step
42+
43+
### The Build Process
44+
1. Create a `prefix` array of the same size as the input.
45+
2. Set `prefix[0] = array[0]`.
46+
3. For each index `i` from `1` to `n-1`:
47+
- `prefix[i] = prefix[i-1] + array[i]`
48+
4. **To Query (L, R):**
49+
- If `L == 0`: Return `prefix[R]`
50+
- Else: Return `prefix[R] - prefix[L-1]`
51+
52+
---
53+
54+
## Implementation
55+
56+
### C++ Code
57+
```cpp
58+
#include <vector>
59+
using namespace std;
60+
61+
// O(N) Preprocessing
62+
vector<long long> buildPrefixSum(const vector<int>& arr) {
63+
int n = arr.size();
64+
if (n == 0) return {};
65+
66+
vector<long long> prefix(n);
67+
prefix[0] = arr[0];
68+
69+
for (int i = 1; i < n; i++) {
70+
prefix[i] = prefix[i - 1] + arr[i];
71+
}
72+
return prefix;
73+
}
74+
75+
// O(1) Query
76+
long long rangeSum(const vector<long long>& prefix, int L, int R) {
77+
if (L == 0) return prefix[R];
78+
return prefix[R] - prefix[L - 1];
79+
}
80+
```
81+
---
82+
83+
## Example Walkthrough & Visualizer
84+
85+
### Dataset Step-by-Step
86+
**Input Array:** `[2, -1, 3, 5, -2, 4]`
87+
88+
89+
90+
| Index | Value (A) | Calculation | **Prefix Sum (P)** |
91+
| :--- | :--- | :--- | :--- |
92+
| 0 | 2 | 2 | **2** |
93+
| 1 | -1 | 2 + (-1) | **1** |
94+
| 2 | 3 | 1 + 3 | **4** |
95+
| 3 | 5 | 4 + 5 | **9** |
96+
| 4 | -2 | 9 + (-2) | **7** |
97+
| 5 | 4 | 7 + 4 | **11** |
98+
99+
### Query Example
100+
**Problem:** Find the sum of elements from index **2** to **5**.
101+
- **Variables:** `L = 2, R = 5`
102+
- **Formula:** `P[R] - P[L-1]`
103+
- **Substitution:** `P[5] - P[1]` $\rightarrow$ `11 - 1`
104+
- **Result:** **10**
105+
106+
*Manual Verification:* `3 + 5 + (-2) + 4 = 10`. ✅
107+
108+
### 🎥 Interactive Trace
109+
To see this accumulation and subtraction logic in action with custom data, use the interactive tool:
110+
👉 **[Prefix Sum Visualizer](https://pholio.pearl99z.tech/extensions/prefixsum)**
111+
112+
---
113+
114+
## Complexity Analysis
115+
116+
| Phase | Time Complexity | Space Complexity |
117+
| :--- | :--- | :--- |
118+
| **Preprocessing (Building)** | `O(N)` | `O(N)` |
119+
| **Range Query** | `O(1)` | `O(1)` |
120+
121+
> **Trade-off:** We use `O(N)` extra space to achieve the fastest possible query time.
122+
123+
---
124+
125+
## Practical Considerations & Edge Cases
126+
127+
### The Zero-Index Trap (`L = 0`)
128+
When `L = 0`, the formula `P[R] - P[L-1]` attempts to access `P[-1]`, which will cause a segmentation fault or crash.
129+
**Solution:**
130+
```cpp
131+
if (L == 0) return prefix[R];
132+
else return prefix[R] - prefix[L-1];
133+
```
134+
## ⚠️ Integer Overflow
135+
136+
For large arrays (e.g., `N = 10^5`) with large values (e.g., `A[i] = 10^9`), the cumulative sum can exceed the 32-bit integer limit (`2,147,483,647`).
137+
138+
**Solution:**
139+
- Use `long long` in **C++**
140+
- Use `long` in **Java**
141+
142+
---
143+
144+
## When to Use vs. When Not to Use
145+
146+
### Use When:
147+
- The array is **static** (no updates).
148+
- You have **many range queries**.
149+
- You are solving **subarray-related problems**.
150+
151+
### Do NOT Use When:
152+
- The array is **frequently updated**.
153+
154+
---
155+
156+
## Practice Problems
157+
158+
| # | Problem | Difficulty |
159+
|---|--------|------------|
160+
| 1 | [Problem 1](#) | Easy |
161+
| 2 | [Problem 2](#) | Easy |
162+
| 3 | [Problem 3](#) | Medium |
163+
| 4 | [Problem 4](#) | Medium |
164+
| 5 | [Problem 5](#) | Hard |
165+
| 6 | [Problem 6](#) | Hard |
166+
167+
168+
## Alternative Data Structures
169+
170+
- **Fenwick Tree (Binary Indexed Tree)**
171+
- **Segment Tree**
172+
173+
Both support **updates and queries in `O(log N)` time**.
174+
175+

0 commit comments

Comments
 (0)