[AI] build roadmap for learning

This commit is contained in:
2026-05-17 01:43:29 +03:00
parent 77824baa7c
commit a1bdd7b879
11 changed files with 2409 additions and 0 deletions
+357
View File
@@ -0,0 +1,357 @@
# Prefix Sum Pattern
## Overview
Prefix sum is a powerful technique for efficiently answering range sum queries and solving various array problems. It involves precomputing cumulative sums to allow O(1) range queries.
## Core Concepts
### Prefix Sum Definition
The prefix sum array `prefix` is defined such that:
```
prefix[i] = arr[0] + arr[1] + ... + arr[i]
```
Given a range query from index `i` to `j`:
```
sum(i, j) = prefix[j] - prefix[i-1]
```
### Basic Implementation
```typescript
function buildPrefixSum(arr: number[]): number[] {
const prefix = new Array(arr.length);
prefix[0] = arr[0];
for (let i = 1; i < arr.length; i++) {
prefix[i] = prefix[i-1] + arr[i];
}
return prefix;
}
function rangeSum(prefix: number[], left: number, right: number): number {
if (left === 0) {
return prefix[right];
}
return prefix[right] - prefix[left-1];
}
```
## Variations
### 1. Prefix Product
```typescript
function buildPrefixProduct(arr: number[]): number[] {
const prefix = new Array(arr.length);
prefix[0] = arr[0];
for (let i = 1; i < arr.length; i++) {
prefix[i] = prefix[i-1] * arr[i];
}
return prefix;
}
function rangeProduct(prefix: number[], left: number, right: number): number {
if (left === 0) {
return prefix[right];
}
return prefix[right] / prefix[left-1];
}
```
### 2. 2D Prefix Sum
```typescript
function build2DPrefixSum(matrix: number[][]): number[][] {
const rows = matrix.length;
const cols = matrix[0].length;
const prefix = Array.from({ length: rows + 1 }, () => Array(cols + 1).fill(0));
for (let i = 1; i <= rows; i++) {
for (let j = 1; j <= cols; j++) {
prefix[i][j] = matrix[i-1][j-1] +
prefix[i-1][j] +
prefix[i][j-1] -
prefix[i-1][j-1];
}
}
return prefix;
}
function range2DSum(prefix: number[][], row1: number, col1: number, row2: number, col2: number): number {
return prefix[row2+1][col2+1] -
prefix[row1][col2+1] -
prefix[row2+1][col1] +
prefix[row1][col1];
}
```
### 3. Prefix XOR
```typescript
function buildPrefixXOR(arr: number[]): number[] {
const prefix = new Array(arr.length);
prefix[0] = arr[0];
for (let i = 1; i < arr.length; i++) {
prefix[i] = prefix[i-1] ^ arr[i];
}
return prefix;
}
function rangeXOR(prefix: number[], left: number, right: number): number {
if (left === 0) {
return prefix[right];
}
return prefix[right] ^ prefix[left-1];
}
```
## Applications
### 1. Subarray Sum Equals K
```typescript
function subarraySum(nums: number[], k: number): number {
const prefixSum = { 0: 1 };
let currentSum = 0;
let count = 0;
for (const num of nums) {
currentSum += num;
// Check if there's a prefix that sums to currentSum - k
if (prefixSum[currentSum - k]) {
count += prefixSum[currentSum - k];
}
// Store current prefix sum
prefixSum[currentSum] = (prefixSum[currentSum] || 0) + 1;
}
return count;
}
```
### 2. Find Maximum Subarray Sum
```typescript
function maxSubArray(nums: number[]): number {
let maxSum = nums[0];
let currentSum = nums[0];
for (let i = 1; i < nums.length; i++) {
currentSum = Math.max(nums[i], currentSum + nums[i]);
maxSum = Math.max(maxSum, currentSum);
}
return maxSum;
}
```
### 3. Product of Array Except Self
```typescript
function productExceptSelf(nums: number[]): number[] {
const n = nums.length;
const left = new Array(n);
const right = new Array(n);
const result = new Array(n);
// Left prefix products
left[0] = 1;
for (let i = 1; i < n; i++) {
left[i] = left[i-1] * nums[i-1];
}
// Right prefix products
right[n-1] = 1;
for (let i = n-2; i >= 0; i--) {
right[i] = right[i+1] * nums[i+1];
}
// Result is product of left and right
for (let i = 0; i < n; i++) {
result[i] = left[i] * right[i];
}
return result;
}
```
## Time Complexity Analysis
| Operation | Time Complexity | Space Complexity | Notes |
|-----------|----------------|----------------|---------|
| Build Prefix Sum | O(n) | O(n) | One pass through array |
| Range Query | O(1) | O(1) | Constant time lookup |
| 2D Prefix Sum | O(mn) | O(mn) | For m×n matrix |
| 2D Range Query | O(1) | O(1) | Rectangle sum query |
## Best Practices
### 1. Handling Edge Cases
```typescript
// Handle empty array
if (arr.length === 0) return [];
// Handle single element
if (arr.length === 1) return [arr[0]];
// Handle negative numbers
// Prefix sum works with negatives too
```
### 2. Space Optimization
```typescript
// In-place prefix sum (if input can be modified)
for (let i = 1; i < arr.length; i++) {
arr[i] += arr[i-1];
}
```
### 3. Multiple Prefix Arrays
```typescript
// For different operations, build separate prefix arrays
const sumPrefix = buildPrefixSum(arr);
const xorPrefix = buildPrefixXOR(arr);
```
## Common Mistakes
### 1. Index Errors
```typescript
// Wrong: off-by-one error
prefix[i] = prefix[i] + arr[i]; // Should use i-1
// Correct: proper indexing
prefix[i] = prefix[i-1] + arr[i];
```
### 2. Range Query Errors
```typescript
// Wrong: incorrect range calculation
sum = prefix[right] - prefix[left]; // Misses left element
// Correct: proper range calculation
sum = prefix[right] - prefix[left-1];
```
### 3. Integer Overflow
```typescript
// Problem: Large numbers can cause overflow
// Solution: Use BigInt or modulo operation
const prefix = new Array(n).fill(BigInt(0));
```
### 4. Not Handling Negative Numbers
```typescript
// Prefix sums work with negatives automatically
// No special handling needed
```
## Practice Problems
### Easy
- [ ] Range sum query
- [ ] Prefix sum array construction
- [ ] Sum of subarray
- [ ] Product of array except self
- [ ] Find pivot index
### Medium
- [ ] Subarray sum equals K
- [ Maximum subarray (Kadane's algorithm)
- [ ] Contiguous array
- [ ] Find the shortest subarray
- [ ] Minimum size subarray sum
### Hard
- [ ] Maximum sum circular subarray
- [ ] Subarray product less than K
- [ ] Find longest subarray with equal 0s and 1s
- [ ] 2D range sum queries
- [ ] Range sum query 2D (immutable)
## Real-world Applications
1. **Data Analysis**: Time series analysis, moving averages
2. **Image Processing**: Integral images for fast feature computation
3. **Database Queries**: Range queries on indexed data
4. **Game Development**: Collision detection, spatial queries
## Advanced Techniques
### 1. Dynamic Programming with Prefix Sums
```typescript
function countSubarrays(arr: number[], target: number): number {
const prefixMap = new Map<number, number>();
prefixMap.set(0, 1);
let currentSum = 0;
let count = 0;
for (let i = 0; i < arr.length; i++) {
currentSum += arr[i];
// Find how many times currentSum - target has occurred
if (prefixMap.has(currentSum - target)) {
count += prefixMap.get(currentSum - target);
}
// Update prefix map
prefixMap.set(currentSum, (prefixMap.get(currentSum) || 0) + 1);
}
return count;
}
```
### 2. Sliding Window with Prefix Sums
```typescript
function findMaxAverage(nums: number[], k: number): number {
// Build prefix sum
const prefix = new Array(nums.length);
prefix[0] = nums[0];
for (let i = 1; i < nums.length; i++) {
prefix[i] = prefix[i-1] + nums[i];
}
let maxSum = prefix[k-1];
for (let i = k; i < nums.length; i++) {
const currentSum = prefix[i] - prefix[i-k];
maxSum = Math.max(maxSum, currentSum);
}
return maxSum / k;
}
```
## Tips for Mastery
### 1. Understand the Mathematics
- Prefix sum is cumulative addition
- Range queries use the inclusion-exclusion principle
- The technique works for any associative operation (sum, product, min, max)
### 2. Practice Different Operations
- Sum, product, XOR, min, max
- 1D and 2D applications
- Dynamic programming combinations
### 3. Optimize Space
- In-place modifications when possible
- Single pass algorithms
- Space-efficient data structures
### 4. Combine with Other Patterns
- Sliding window
- Binary search
- Hash tables for frequency counting
## Next Steps
1. Master basic prefix sum construction and queries
2. Practice 1D and 2D applications
3. Learn to combine with dynamic programming
4. Apply to real-world problems
---
**Key Takeaway**: Prefix sum is a fundamental technique for range queries and subarray problems. It transforms O(n) range queries into O(1) operations with O(n) preprocessing time. Always consider prefix sums when dealing with range-based array problems.