claude-agent-framework 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +128 -0
- package/bin/claude-framework +3 -0
- package/framework/agents/design-lead.md +240 -0
- package/framework/agents/product-owner.md +179 -0
- package/framework/agents/tech-lead.md +226 -0
- package/framework/commands/ayuda.md +127 -0
- package/framework/commands/a/303/261adir.md +98 -0
- package/framework/commands/backup.md +397 -0
- package/framework/commands/cambiar.md +110 -0
- package/framework/commands/cloud.md +457 -0
- package/framework/commands/code.md +142 -0
- package/framework/commands/debug.md +334 -0
- package/framework/commands/deploy.md +383 -0
- package/framework/commands/deshacer.md +120 -0
- package/framework/commands/estado.md +218 -0
- package/framework/commands/explica.md +227 -0
- package/framework/commands/feature.md +120 -0
- package/framework/commands/git.md +427 -0
- package/framework/commands/historial.md +202 -0
- package/framework/commands/learn.md +408 -0
- package/framework/commands/movil.md +245 -0
- package/framework/commands/nuevo.md +118 -0
- package/framework/commands/plan.md +134 -0
- package/framework/commands/prd.md +113 -0
- package/framework/commands/probar.md +148 -0
- package/framework/commands/revisar.md +208 -0
- package/framework/commands/seeds.md +230 -0
- package/framework/commands/seguridad.md +226 -0
- package/framework/commands/tasks.md +157 -0
- package/framework/skills/architecture/algorithms.md +970 -0
- package/framework/skills/architecture/clean-code.md +1080 -0
- package/framework/skills/architecture/design-patterns.md +1984 -0
- package/framework/skills/architecture/functional-programming.md +972 -0
- package/framework/skills/architecture/solid.md +991 -0
- package/framework/skills/cloud/cloud-aws.md +848 -0
- package/framework/skills/cloud/cloud-azure.md +931 -0
- package/framework/skills/cloud/cloud-gcp.md +848 -0
- package/framework/skills/cloud/message-queues.md +1229 -0
- package/framework/skills/core/accessibility.md +401 -0
- package/framework/skills/core/api.md +474 -0
- package/framework/skills/core/authentication.md +306 -0
- package/framework/skills/core/authorization.md +388 -0
- package/framework/skills/core/background-jobs.md +341 -0
- package/framework/skills/core/caching.md +473 -0
- package/framework/skills/core/code-review.md +341 -0
- package/framework/skills/core/controllers.md +290 -0
- package/framework/skills/core/cua.md +285 -0
- package/framework/skills/core/documentation.md +472 -0
- package/framework/skills/core/file-uploads.md +351 -0
- package/framework/skills/core/hotwire-native.md +296 -0
- package/framework/skills/core/hotwire.md +278 -0
- package/framework/skills/core/i18n.md +334 -0
- package/framework/skills/core/imports-exports.md +750 -0
- package/framework/skills/core/infrastructure.md +337 -0
- package/framework/skills/core/models.md +228 -0
- package/framework/skills/core/notifications.md +672 -0
- package/framework/skills/core/payments.md +581 -0
- package/framework/skills/core/performance.md +361 -0
- package/framework/skills/core/rails-scaffold.md +131 -0
- package/framework/skills/core/search.md +518 -0
- package/framework/skills/core/security.md +565 -0
- package/framework/skills/core/seeds.md +307 -0
- package/framework/skills/core/seo.md +542 -0
- package/framework/skills/core/testing.md +393 -0
- package/framework/skills/core/views.md +260 -0
- package/framework/skills/core/websockets.md +564 -0
- package/framework/skills/data/advanced-sql.md +1204 -0
- package/framework/skills/data/nosql.md +1141 -0
- package/framework/skills/devops/containers-advanced.md +1237 -0
- package/framework/skills/devops/debugging.md +834 -0
- package/framework/skills/devops/git-workflow.md +752 -0
- package/framework/skills/devops/networking.md +932 -0
- package/framework/skills/devops/shell-scripting.md +1132 -0
- package/framework/sub-agents/architecture-patterns-agent.md +1450 -0
- package/framework/sub-agents/cloud-agent.md +677 -0
- package/framework/sub-agents/data.md +504 -0
- package/framework/sub-agents/debugging-agent.md +554 -0
- package/framework/sub-agents/devops.md +483 -0
- package/framework/sub-agents/docs.md +176 -0
- package/framework/sub-agents/frontend-dev.md +349 -0
- package/framework/sub-agents/git-workflow-agent.md +697 -0
- package/framework/sub-agents/integrations.md +630 -0
- package/framework/sub-agents/native-dev.md +434 -0
- package/framework/sub-agents/qa.md +138 -0
- package/framework/sub-agents/rails-dev.md +375 -0
- package/framework/sub-agents/security.md +526 -0
- package/framework/sub-agents/ui.md +437 -0
- package/framework/sub-agents/ux.md +284 -0
- package/framework/templates/api-spec.md +500 -0
- package/framework/templates/component-spec.md +248 -0
- package/framework/templates/feature.json +13 -0
- package/framework/templates/model-spec.md +318 -0
- package/framework/templates/prd-template.md +80 -0
- package/framework/templates/task-plan.md +122 -0
- package/framework/templates/task-user-story.md +52 -0
- package/framework/templates/technical-spec.md +260 -0
- package/framework/templates/user-story.md +95 -0
- package/package.json +42 -0
- package/project-templates/CLAUDE.md +42 -0
- package/project-templates/contexts/architecture.md +25 -0
- package/project-templates/contexts/conventions.md +46 -0
- package/project-templates/contexts/design-system.md +47 -0
- package/project-templates/contexts/requirements.md +38 -0
- package/project-templates/contexts/stack.md +30 -0
- package/project-templates/history/active/models.md +11 -0
- package/project-templates/history/changelog.md +15 -0
- package/project-templates/workspace/.gitkeep +0 -0
- package/src/cli.js +52 -0
- package/src/init.js +104 -0
- package/src/status.js +75 -0
- package/src/update.js +88 -0
|
@@ -0,0 +1,970 @@
|
|
|
1
|
+
# Skill: Algorithms and Data Structures
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
Understand algorithmic complexity and choose appropriate data structures for efficient Ruby and Rails applications.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Big O Notation
|
|
9
|
+
|
|
10
|
+
### Common Complexities
|
|
11
|
+
```
|
|
12
|
+
O(1) - Constant - Hash lookup, array access by index
|
|
13
|
+
O(log n) - Logarithmic - Binary search, balanced tree operations
|
|
14
|
+
O(n) - Linear - Array iteration, linear search
|
|
15
|
+
O(n log n) - Linearithmic - Efficient sorting (merge sort, quick sort)
|
|
16
|
+
O(n²) - Quadratic - Nested loops, bubble sort
|
|
17
|
+
O(2ⁿ) - Exponential - Recursive fibonacci (naive), power set
|
|
18
|
+
O(n!) - Factorial - Permutations, traveling salesman (brute force)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Visual Comparison
|
|
22
|
+
```
|
|
23
|
+
n=10: O(1)=1 O(log n)=3 O(n)=10 O(n log n)=33 O(n²)=100
|
|
24
|
+
n=100: O(1)=1 O(log n)=7 O(n)=100 O(n log n)=664 O(n²)=10,000
|
|
25
|
+
n=1000: O(1)=1 O(log n)=10 O(n)=1000 O(n log n)=9,966 O(n²)=1,000,000
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Examples in Ruby
|
|
29
|
+
```ruby
|
|
30
|
+
# O(1) - Constant time
|
|
31
|
+
hash = { a: 1, b: 2, c: 3 }
|
|
32
|
+
hash[:b] # Hash lookup
|
|
33
|
+
array[5] # Array access by index
|
|
34
|
+
array.push(item) # Array append
|
|
35
|
+
array.pop # Array pop
|
|
36
|
+
|
|
37
|
+
# O(log n) - Logarithmic
|
|
38
|
+
sorted_array.bsearch { |x| x >= target } # Binary search
|
|
39
|
+
# Each step cuts the search space in half
|
|
40
|
+
|
|
41
|
+
# O(n) - Linear
|
|
42
|
+
array.each { |item| process(item) } # Iterate all elements
|
|
43
|
+
array.include?(item) # Linear search
|
|
44
|
+
array.find { |x| x == target } # Find first match
|
|
45
|
+
array.max # Find maximum
|
|
46
|
+
array.sum # Sum all elements
|
|
47
|
+
|
|
48
|
+
# O(n log n) - Linearithmic
|
|
49
|
+
array.sort # Sorting
|
|
50
|
+
array.sort_by { |x| x.name }
|
|
51
|
+
|
|
52
|
+
# O(n²) - Quadratic
|
|
53
|
+
array.each do |a|
|
|
54
|
+
array.each do |b| # Nested loop
|
|
55
|
+
compare(a, b)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# O(2ⁿ) - Exponential (avoid!)
|
|
60
|
+
def fibonacci(n)
|
|
61
|
+
return n if n <= 1
|
|
62
|
+
fibonacci(n - 1) + fibonacci(n - 2) # Each call spawns 2 more
|
|
63
|
+
end
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Analyzing Complexity
|
|
67
|
+
```ruby
|
|
68
|
+
# Rule 1: Drop constants
|
|
69
|
+
# O(2n) -> O(n)
|
|
70
|
+
# O(n/2) -> O(n)
|
|
71
|
+
|
|
72
|
+
# Rule 2: Drop non-dominant terms
|
|
73
|
+
# O(n² + n) -> O(n²)
|
|
74
|
+
# O(n + log n) -> O(n)
|
|
75
|
+
|
|
76
|
+
# Rule 3: Different inputs = different variables
|
|
77
|
+
def compare_lists(list_a, list_b)
|
|
78
|
+
list_a.each do |a| # O(a)
|
|
79
|
+
list_b.each do |b| # O(b)
|
|
80
|
+
puts a == b
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
# Total: O(a * b), not O(n²)
|
|
85
|
+
|
|
86
|
+
# Rule 4: Sequential operations add
|
|
87
|
+
def process(array)
|
|
88
|
+
array.each { |x| step1(x) } # O(n)
|
|
89
|
+
array.each { |x| step2(x) } # O(n)
|
|
90
|
+
end
|
|
91
|
+
# Total: O(n + n) = O(2n) = O(n)
|
|
92
|
+
|
|
93
|
+
# Rule 5: Nested operations multiply
|
|
94
|
+
def process(array)
|
|
95
|
+
array.each do |x| # O(n)
|
|
96
|
+
array.each { |y| work(x, y) } # O(n)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
# Total: O(n * n) = O(n²)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Arrays vs Hashes
|
|
105
|
+
|
|
106
|
+
### When to Use Arrays
|
|
107
|
+
```ruby
|
|
108
|
+
# Arrays are best for:
|
|
109
|
+
# - Ordered collections
|
|
110
|
+
# - Accessing by position
|
|
111
|
+
# - Iterating in sequence
|
|
112
|
+
# - Small collections with simple lookups
|
|
113
|
+
|
|
114
|
+
# Array operations and complexity
|
|
115
|
+
array = [1, 2, 3, 4, 5]
|
|
116
|
+
|
|
117
|
+
array[0] # O(1) - Access by index
|
|
118
|
+
array.push(6) # O(1) - Append
|
|
119
|
+
array.pop # O(1) - Remove last
|
|
120
|
+
array.shift # O(n) - Remove first (shifts all elements)
|
|
121
|
+
array.unshift(0) # O(n) - Add to front (shifts all elements)
|
|
122
|
+
array.include?(3) # O(n) - Search
|
|
123
|
+
array.index(3) # O(n) - Find index
|
|
124
|
+
array.insert(2, x) # O(n) - Insert at position
|
|
125
|
+
|
|
126
|
+
# Good use case: maintaining order
|
|
127
|
+
recent_items = []
|
|
128
|
+
recent_items.push(item)
|
|
129
|
+
recent_items.shift if recent_items.size > 10 # Keep last 10
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### When to Use Hashes
|
|
133
|
+
```ruby
|
|
134
|
+
# Hashes are best for:
|
|
135
|
+
# - Key-value lookups
|
|
136
|
+
# - Checking membership
|
|
137
|
+
# - Counting occurrences
|
|
138
|
+
# - Caching/memoization
|
|
139
|
+
|
|
140
|
+
# Hash operations and complexity
|
|
141
|
+
hash = { a: 1, b: 2, c: 3 }
|
|
142
|
+
|
|
143
|
+
hash[:a] # O(1) - Lookup
|
|
144
|
+
hash[:d] = 4 # O(1) - Insert
|
|
145
|
+
hash.delete(:a) # O(1) - Delete
|
|
146
|
+
hash.key?(:b) # O(1) - Check key exists
|
|
147
|
+
hash.value?(2) # O(n) - Check value exists (must scan all)
|
|
148
|
+
hash.keys # O(n) - Get all keys
|
|
149
|
+
hash.values # O(n) - Get all values
|
|
150
|
+
|
|
151
|
+
# Good use case: counting
|
|
152
|
+
def count_words(text)
|
|
153
|
+
counts = Hash.new(0)
|
|
154
|
+
text.split.each { |word| counts[word] += 1 }
|
|
155
|
+
counts
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# Good use case: caching
|
|
159
|
+
def expensive_lookup(id)
|
|
160
|
+
@cache ||= {}
|
|
161
|
+
@cache[id] ||= Database.find(id)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Good use case: checking membership
|
|
165
|
+
allowed_ids = { 1 => true, 2 => true, 3 => true }
|
|
166
|
+
allowed_ids[user_id] # O(1) vs array.include? O(n)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Converting Between Them
|
|
170
|
+
```ruby
|
|
171
|
+
# Array to Hash
|
|
172
|
+
array = [[:a, 1], [:b, 2]]
|
|
173
|
+
hash = array.to_h # => { a: 1, b: 2 }
|
|
174
|
+
|
|
175
|
+
# Array to Hash (for membership checking)
|
|
176
|
+
ids = [1, 2, 3, 4, 5]
|
|
177
|
+
id_set = ids.to_h { |id| [id, true] }
|
|
178
|
+
id_set[3] # O(1) lookup
|
|
179
|
+
|
|
180
|
+
# Hash to Array
|
|
181
|
+
hash = { a: 1, b: 2 }
|
|
182
|
+
hash.to_a # => [[:a, 1], [:b, 2]]
|
|
183
|
+
hash.keys # => [:a, :b]
|
|
184
|
+
hash.values # => [1, 2]
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Sorting
|
|
190
|
+
|
|
191
|
+
### Built-in Sorting
|
|
192
|
+
```ruby
|
|
193
|
+
# sort - uses <=> operator
|
|
194
|
+
[3, 1, 4, 1, 5].sort # => [1, 1, 3, 4, 5]
|
|
195
|
+
["banana", "apple"].sort # => ["apple", "banana"]
|
|
196
|
+
|
|
197
|
+
# sort with custom comparator
|
|
198
|
+
[3, 1, 4].sort { |a, b| b <=> a } # Descending: [4, 3, 1]
|
|
199
|
+
|
|
200
|
+
# sort_by - more efficient for complex keys
|
|
201
|
+
users.sort_by { |u| u.name }
|
|
202
|
+
users.sort_by(&:name) # Shorthand
|
|
203
|
+
|
|
204
|
+
# sort_by with multiple keys
|
|
205
|
+
users.sort_by { |u| [u.last_name, u.first_name] }
|
|
206
|
+
|
|
207
|
+
# Descending sort_by
|
|
208
|
+
users.sort_by { |u| -u.age } # Numeric
|
|
209
|
+
users.sort_by { |u| u.name }.reverse # Any type
|
|
210
|
+
|
|
211
|
+
# In-place sorting (mutates)
|
|
212
|
+
array.sort!
|
|
213
|
+
array.sort_by!(&:name)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Custom Comparators
|
|
217
|
+
```ruby
|
|
218
|
+
# The <=> operator returns:
|
|
219
|
+
# -1 if a < b
|
|
220
|
+
# 0 if a == b
|
|
221
|
+
# 1 if a > b
|
|
222
|
+
|
|
223
|
+
class Person
|
|
224
|
+
include Comparable
|
|
225
|
+
|
|
226
|
+
attr_reader :name, :age
|
|
227
|
+
|
|
228
|
+
def initialize(name, age)
|
|
229
|
+
@name = name
|
|
230
|
+
@age = age
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def <=>(other)
|
|
234
|
+
age <=> other.age
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
people = [Person.new("Bob", 30), Person.new("Alice", 25)]
|
|
239
|
+
people.sort # Sorted by age
|
|
240
|
+
|
|
241
|
+
# Complex sorting
|
|
242
|
+
products.sort do |a, b|
|
|
243
|
+
# First by category, then by price descending
|
|
244
|
+
comparison = a.category <=> b.category
|
|
245
|
+
comparison = b.price <=> a.price if comparison == 0
|
|
246
|
+
comparison
|
|
247
|
+
end
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Sorting Stability
|
|
251
|
+
```ruby
|
|
252
|
+
# Ruby's sort is NOT stable (equal elements may change order)
|
|
253
|
+
# Use sort_by for stable-ish sorting or add a tiebreaker
|
|
254
|
+
|
|
255
|
+
# Stable sort workaround
|
|
256
|
+
users_with_index = users.each_with_index.map { |u, i| [u, i] }
|
|
257
|
+
sorted = users_with_index.sort_by { |u, i| [u.name, i] }
|
|
258
|
+
result = sorted.map(&:first)
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## Searching
|
|
264
|
+
|
|
265
|
+
### Linear Search
|
|
266
|
+
```ruby
|
|
267
|
+
# O(n) - checks each element
|
|
268
|
+
array = [3, 1, 4, 1, 5, 9, 2, 6]
|
|
269
|
+
|
|
270
|
+
# find - returns first match or nil
|
|
271
|
+
array.find { |x| x > 4 } # => 5
|
|
272
|
+
|
|
273
|
+
# find_index/index - returns index of first match
|
|
274
|
+
array.find_index { |x| x > 4 } # => 4
|
|
275
|
+
array.index(4) # => 2
|
|
276
|
+
|
|
277
|
+
# include? - checks presence
|
|
278
|
+
array.include?(5) # => true
|
|
279
|
+
|
|
280
|
+
# any?/all?/none?
|
|
281
|
+
array.any? { |x| x > 8 } # => true
|
|
282
|
+
array.all? { |x| x > 0 } # => true
|
|
283
|
+
array.none? { |x| x > 10 } # => true
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Binary Search
|
|
287
|
+
```ruby
|
|
288
|
+
# O(log n) - requires sorted array
|
|
289
|
+
sorted = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
|
290
|
+
|
|
291
|
+
# bsearch - returns element
|
|
292
|
+
sorted.bsearch { |x| x >= 5 } # => 5
|
|
293
|
+
sorted.bsearch { |x| x >= 5.5 } # => 6
|
|
294
|
+
|
|
295
|
+
# bsearch_index - returns index
|
|
296
|
+
sorted.bsearch_index { |x| x >= 5 } # => 4
|
|
297
|
+
|
|
298
|
+
# Find exact match
|
|
299
|
+
sorted.bsearch { |x| x <=> 5 } # => 5 (or nil if not found)
|
|
300
|
+
|
|
301
|
+
# Custom binary search
|
|
302
|
+
def binary_search(array, target)
|
|
303
|
+
low = 0
|
|
304
|
+
high = array.length - 1
|
|
305
|
+
|
|
306
|
+
while low <= high
|
|
307
|
+
mid = (low + high) / 2
|
|
308
|
+
case array[mid] <=> target
|
|
309
|
+
when 0 then return mid
|
|
310
|
+
when -1 then low = mid + 1
|
|
311
|
+
when 1 then high = mid - 1
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
nil # Not found
|
|
316
|
+
end
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### Search in Hashes and Sets
|
|
320
|
+
```ruby
|
|
321
|
+
# Hash - O(1) average
|
|
322
|
+
users_by_email = users.index_by(&:email)
|
|
323
|
+
user = users_by_email["john@example.com"] # O(1)
|
|
324
|
+
|
|
325
|
+
# Set - O(1) for membership
|
|
326
|
+
require 'set'
|
|
327
|
+
valid_ids = Set.new([1, 2, 3, 4, 5])
|
|
328
|
+
valid_ids.include?(3) # O(1)
|
|
329
|
+
|
|
330
|
+
# vs Array.include? which is O(n)
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## Recursion
|
|
336
|
+
|
|
337
|
+
### Basic Recursion
|
|
338
|
+
```ruby
|
|
339
|
+
# Every recursive function needs:
|
|
340
|
+
# 1. Base case - when to stop
|
|
341
|
+
# 2. Recursive case - how to break down the problem
|
|
342
|
+
|
|
343
|
+
# Factorial: n! = n * (n-1) * (n-2) * ... * 1
|
|
344
|
+
def factorial(n)
|
|
345
|
+
return 1 if n <= 1 # Base case
|
|
346
|
+
n * factorial(n - 1) # Recursive case
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
factorial(5) # => 120
|
|
350
|
+
|
|
351
|
+
# Fibonacci (naive - O(2^n), don't use!)
|
|
352
|
+
def fibonacci(n)
|
|
353
|
+
return n if n <= 1 # Base case
|
|
354
|
+
fibonacci(n - 1) + fibonacci(n - 2) # Two recursive calls!
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
# Sum of array
|
|
358
|
+
def sum(array)
|
|
359
|
+
return 0 if array.empty? # Base case
|
|
360
|
+
array.first + sum(array[1..]) # Recursive case
|
|
361
|
+
end
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Tail Recursion
|
|
365
|
+
```ruby
|
|
366
|
+
# Regular recursion - builds up call stack
|
|
367
|
+
def factorial(n)
|
|
368
|
+
return 1 if n <= 1
|
|
369
|
+
n * factorial(n - 1) # Must wait for recursive call to complete
|
|
370
|
+
end
|
|
371
|
+
# Stack: factorial(5) -> factorial(4) -> factorial(3) -> ...
|
|
372
|
+
|
|
373
|
+
# Tail recursion - last operation is the recursive call
|
|
374
|
+
def factorial_tail(n, accumulator = 1)
|
|
375
|
+
return accumulator if n <= 1
|
|
376
|
+
factorial_tail(n - 1, n * accumulator) # Tail position
|
|
377
|
+
end
|
|
378
|
+
# Can be optimized to O(1) space (Ruby doesn't do this automatically)
|
|
379
|
+
|
|
380
|
+
# Enable tail call optimization (experimental)
|
|
381
|
+
RubyVM::InstructionSequence.compile_option = {
|
|
382
|
+
tailcall_optimization: true,
|
|
383
|
+
trace_instruction: false
|
|
384
|
+
}
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### Converting Recursion to Iteration
|
|
388
|
+
```ruby
|
|
389
|
+
# Recursive
|
|
390
|
+
def sum_recursive(array)
|
|
391
|
+
return 0 if array.empty?
|
|
392
|
+
array.first + sum_recursive(array[1..])
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
# Iterative (usually more efficient in Ruby)
|
|
396
|
+
def sum_iterative(array)
|
|
397
|
+
total = 0
|
|
398
|
+
array.each { |x| total += x }
|
|
399
|
+
total
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
# Or simply
|
|
403
|
+
array.sum
|
|
404
|
+
|
|
405
|
+
# Recursive tree traversal
|
|
406
|
+
def traverse_recursive(node)
|
|
407
|
+
return if node.nil?
|
|
408
|
+
process(node)
|
|
409
|
+
node.children.each { |child| traverse_recursive(child) }
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
# Iterative with stack
|
|
413
|
+
def traverse_iterative(root)
|
|
414
|
+
stack = [root]
|
|
415
|
+
while stack.any?
|
|
416
|
+
node = stack.pop
|
|
417
|
+
process(node)
|
|
418
|
+
stack.concat(node.children.reverse)
|
|
419
|
+
end
|
|
420
|
+
end
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
---
|
|
424
|
+
|
|
425
|
+
## Memoization
|
|
426
|
+
|
|
427
|
+
### Using ||= for Simple Memoization
|
|
428
|
+
```ruby
|
|
429
|
+
class ExpensiveCalculator
|
|
430
|
+
def result
|
|
431
|
+
@result ||= calculate # Only calculates once
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
# Handle nil and false
|
|
435
|
+
def value
|
|
436
|
+
return @value if defined?(@value)
|
|
437
|
+
@value = calculate_value
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
private
|
|
441
|
+
|
|
442
|
+
def calculate
|
|
443
|
+
sleep(2) # Expensive operation
|
|
444
|
+
42
|
|
445
|
+
end
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
# Memoizing methods with arguments
|
|
449
|
+
class Fibonacci
|
|
450
|
+
def initialize
|
|
451
|
+
@cache = {}
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
def calculate(n)
|
|
455
|
+
@cache[n] ||= begin
|
|
456
|
+
return n if n <= 1
|
|
457
|
+
calculate(n - 1) + calculate(n - 2)
|
|
458
|
+
end
|
|
459
|
+
end
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
fib = Fibonacci.new
|
|
463
|
+
fib.calculate(100) # Fast! O(n) instead of O(2^n)
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
### Using Rails.cache
|
|
467
|
+
```ruby
|
|
468
|
+
# Simple caching
|
|
469
|
+
def expensive_query
|
|
470
|
+
Rails.cache.fetch("expensive_query", expires_in: 1.hour) do
|
|
471
|
+
User.includes(:orders, :subscriptions).where(active: true).to_a
|
|
472
|
+
end
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
# Cache with key based on data
|
|
476
|
+
def user_stats(user)
|
|
477
|
+
Rails.cache.fetch("user_stats/#{user.id}/#{user.updated_at.to_i}") do
|
|
478
|
+
calculate_stats(user)
|
|
479
|
+
end
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
# Russian doll caching in views
|
|
483
|
+
<% cache @product do %>
|
|
484
|
+
<% @product.variants.each do |variant| %>
|
|
485
|
+
<% cache variant do %>
|
|
486
|
+
<%= render variant %>
|
|
487
|
+
<% end %>
|
|
488
|
+
<% end %>
|
|
489
|
+
<% end %>
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
### Memoization Patterns
|
|
493
|
+
```ruby
|
|
494
|
+
# Class-level memoization for constants
|
|
495
|
+
class TaxCalculator
|
|
496
|
+
def self.rates
|
|
497
|
+
@rates ||= TaxRate.all.index_by(&:region).freeze
|
|
498
|
+
end
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
# Thread-safe memoization
|
|
502
|
+
class Configuration
|
|
503
|
+
def self.settings
|
|
504
|
+
@settings_mutex ||= Mutex.new
|
|
505
|
+
@settings ||= @settings_mutex.synchronize do
|
|
506
|
+
@settings || load_settings
|
|
507
|
+
end
|
|
508
|
+
end
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
# Per-request memoization (Rails)
|
|
512
|
+
class ApplicationController
|
|
513
|
+
def current_user
|
|
514
|
+
@current_user ||= User.find(session[:user_id])
|
|
515
|
+
end
|
|
516
|
+
end
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
---
|
|
520
|
+
|
|
521
|
+
## Data Structures
|
|
522
|
+
|
|
523
|
+
### Stack (LIFO)
|
|
524
|
+
```ruby
|
|
525
|
+
# Using Array as stack
|
|
526
|
+
stack = []
|
|
527
|
+
stack.push(1) # Add to top
|
|
528
|
+
stack.push(2)
|
|
529
|
+
stack.push(3)
|
|
530
|
+
stack.pop # => 3 (remove from top)
|
|
531
|
+
stack.last # => 2 (peek)
|
|
532
|
+
stack.empty? # => false
|
|
533
|
+
|
|
534
|
+
# Use case: parsing nested structures
|
|
535
|
+
def valid_parentheses?(string)
|
|
536
|
+
stack = []
|
|
537
|
+
pairs = { ")" => "(", "]" => "[", "}" => "{" }
|
|
538
|
+
|
|
539
|
+
string.each_char do |char|
|
|
540
|
+
if pairs.values.include?(char)
|
|
541
|
+
stack.push(char)
|
|
542
|
+
elsif pairs.keys.include?(char)
|
|
543
|
+
return false if stack.pop != pairs[char]
|
|
544
|
+
end
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
stack.empty?
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
valid_parentheses?("([{}])") # => true
|
|
551
|
+
valid_parentheses?("([)]") # => false
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
### Queue (FIFO)
|
|
555
|
+
```ruby
|
|
556
|
+
# Using Array as queue (inefficient for large queues)
|
|
557
|
+
queue = []
|
|
558
|
+
queue.push(1) # Enqueue
|
|
559
|
+
queue.push(2)
|
|
560
|
+
queue.shift # => 1 (dequeue)
|
|
561
|
+
|
|
562
|
+
# Better: Use Queue class for thread safety
|
|
563
|
+
require 'thread'
|
|
564
|
+
queue = Queue.new
|
|
565
|
+
queue << 1 # Enqueue
|
|
566
|
+
queue.pop # Dequeue (blocks if empty)
|
|
567
|
+
queue.pop(true) # Non-blocking (raises if empty)
|
|
568
|
+
|
|
569
|
+
# Use case: BFS traversal
|
|
570
|
+
def breadth_first_search(root, target)
|
|
571
|
+
queue = [root]
|
|
572
|
+
|
|
573
|
+
while queue.any?
|
|
574
|
+
node = queue.shift
|
|
575
|
+
return node if node.value == target
|
|
576
|
+
queue.concat(node.children)
|
|
577
|
+
end
|
|
578
|
+
|
|
579
|
+
nil
|
|
580
|
+
end
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
### Linked List
|
|
584
|
+
```ruby
|
|
585
|
+
# Ruby arrays are dynamic, but linked lists are useful to understand
|
|
586
|
+
class Node
|
|
587
|
+
attr_accessor :value, :next_node
|
|
588
|
+
|
|
589
|
+
def initialize(value)
|
|
590
|
+
@value = value
|
|
591
|
+
@next_node = nil
|
|
592
|
+
end
|
|
593
|
+
end
|
|
594
|
+
|
|
595
|
+
class LinkedList
|
|
596
|
+
def initialize
|
|
597
|
+
@head = nil
|
|
598
|
+
end
|
|
599
|
+
|
|
600
|
+
def append(value)
|
|
601
|
+
new_node = Node.new(value)
|
|
602
|
+
if @head.nil?
|
|
603
|
+
@head = new_node
|
|
604
|
+
else
|
|
605
|
+
current = @head
|
|
606
|
+
current = current.next_node while current.next_node
|
|
607
|
+
current.next_node = new_node
|
|
608
|
+
end
|
|
609
|
+
end
|
|
610
|
+
|
|
611
|
+
def each
|
|
612
|
+
current = @head
|
|
613
|
+
while current
|
|
614
|
+
yield current.value
|
|
615
|
+
current = current.next_node
|
|
616
|
+
end
|
|
617
|
+
end
|
|
618
|
+
end
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
### Tree
|
|
622
|
+
```ruby
|
|
623
|
+
class TreeNode
|
|
624
|
+
attr_accessor :value, :children
|
|
625
|
+
|
|
626
|
+
def initialize(value)
|
|
627
|
+
@value = value
|
|
628
|
+
@children = []
|
|
629
|
+
end
|
|
630
|
+
|
|
631
|
+
def add_child(value)
|
|
632
|
+
child = TreeNode.new(value)
|
|
633
|
+
@children << child
|
|
634
|
+
child
|
|
635
|
+
end
|
|
636
|
+
|
|
637
|
+
# Depth-first traversal
|
|
638
|
+
def each_dfs(&block)
|
|
639
|
+
block.call(self)
|
|
640
|
+
@children.each { |child| child.each_dfs(&block) }
|
|
641
|
+
end
|
|
642
|
+
|
|
643
|
+
# Breadth-first traversal
|
|
644
|
+
def each_bfs
|
|
645
|
+
queue = [self]
|
|
646
|
+
while queue.any?
|
|
647
|
+
node = queue.shift
|
|
648
|
+
yield node
|
|
649
|
+
queue.concat(node.children)
|
|
650
|
+
end
|
|
651
|
+
end
|
|
652
|
+
end
|
|
653
|
+
|
|
654
|
+
# Binary Tree
|
|
655
|
+
class BinaryTreeNode
|
|
656
|
+
attr_accessor :value, :left, :right
|
|
657
|
+
|
|
658
|
+
def initialize(value)
|
|
659
|
+
@value = value
|
|
660
|
+
end
|
|
661
|
+
|
|
662
|
+
# In-order traversal (left, root, right)
|
|
663
|
+
def in_order(&block)
|
|
664
|
+
@left&.in_order(&block)
|
|
665
|
+
block.call(@value)
|
|
666
|
+
@right&.in_order(&block)
|
|
667
|
+
end
|
|
668
|
+
|
|
669
|
+
# Pre-order traversal (root, left, right)
|
|
670
|
+
def pre_order(&block)
|
|
671
|
+
block.call(@value)
|
|
672
|
+
@left&.pre_order(&block)
|
|
673
|
+
@right&.pre_order(&block)
|
|
674
|
+
end
|
|
675
|
+
|
|
676
|
+
# Post-order traversal (left, right, root)
|
|
677
|
+
def post_order(&block)
|
|
678
|
+
@left&.post_order(&block)
|
|
679
|
+
@right&.post_order(&block)
|
|
680
|
+
block.call(@value)
|
|
681
|
+
end
|
|
682
|
+
end
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
### Graph
|
|
686
|
+
```ruby
|
|
687
|
+
class Graph
|
|
688
|
+
def initialize
|
|
689
|
+
@adjacency_list = Hash.new { |h, k| h[k] = [] }
|
|
690
|
+
end
|
|
691
|
+
|
|
692
|
+
def add_edge(from, to, directed: false)
|
|
693
|
+
@adjacency_list[from] << to
|
|
694
|
+
@adjacency_list[to] << from unless directed
|
|
695
|
+
end
|
|
696
|
+
|
|
697
|
+
def neighbors(node)
|
|
698
|
+
@adjacency_list[node]
|
|
699
|
+
end
|
|
700
|
+
|
|
701
|
+
# Breadth-First Search
|
|
702
|
+
def bfs(start)
|
|
703
|
+
visited = Set.new([start])
|
|
704
|
+
queue = [start]
|
|
705
|
+
result = []
|
|
706
|
+
|
|
707
|
+
while queue.any?
|
|
708
|
+
node = queue.shift
|
|
709
|
+
result << node
|
|
710
|
+
|
|
711
|
+
neighbors(node).each do |neighbor|
|
|
712
|
+
unless visited.include?(neighbor)
|
|
713
|
+
visited << neighbor
|
|
714
|
+
queue << neighbor
|
|
715
|
+
end
|
|
716
|
+
end
|
|
717
|
+
end
|
|
718
|
+
|
|
719
|
+
result
|
|
720
|
+
end
|
|
721
|
+
|
|
722
|
+
# Depth-First Search
|
|
723
|
+
def dfs(start, visited = Set.new)
|
|
724
|
+
return [] if visited.include?(start)
|
|
725
|
+
|
|
726
|
+
visited << start
|
|
727
|
+
result = [start]
|
|
728
|
+
|
|
729
|
+
neighbors(start).each do |neighbor|
|
|
730
|
+
result.concat(dfs(neighbor, visited))
|
|
731
|
+
end
|
|
732
|
+
|
|
733
|
+
result
|
|
734
|
+
end
|
|
735
|
+
end
|
|
736
|
+
|
|
737
|
+
# Usage
|
|
738
|
+
graph = Graph.new
|
|
739
|
+
graph.add_edge("A", "B")
|
|
740
|
+
graph.add_edge("A", "C")
|
|
741
|
+
graph.add_edge("B", "D")
|
|
742
|
+
graph.add_edge("C", "D")
|
|
743
|
+
|
|
744
|
+
graph.bfs("A") # => ["A", "B", "C", "D"]
|
|
745
|
+
graph.dfs("A") # => ["A", "B", "D", "C"]
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
---
|
|
749
|
+
|
|
750
|
+
## Ruby Collections
|
|
751
|
+
|
|
752
|
+
### Set
|
|
753
|
+
```ruby
|
|
754
|
+
require 'set'
|
|
755
|
+
|
|
756
|
+
# Create a set
|
|
757
|
+
set = Set.new([1, 2, 3, 2, 1]) # => #<Set: {1, 2, 3}>
|
|
758
|
+
|
|
759
|
+
# Operations - all O(1) average
|
|
760
|
+
set.add(4) # Add element
|
|
761
|
+
set.delete(2) # Remove element
|
|
762
|
+
set.include?(3) # Check membership
|
|
763
|
+
|
|
764
|
+
# Set operations
|
|
765
|
+
a = Set.new([1, 2, 3])
|
|
766
|
+
b = Set.new([2, 3, 4])
|
|
767
|
+
|
|
768
|
+
a | b # Union: {1, 2, 3, 4}
|
|
769
|
+
a & b # Intersection: {2, 3}
|
|
770
|
+
a - b # Difference: {1}
|
|
771
|
+
a ^ b # Symmetric difference: {1, 4}
|
|
772
|
+
|
|
773
|
+
# Use case: efficient membership checking
|
|
774
|
+
valid_statuses = Set.new(%w[pending active completed])
|
|
775
|
+
valid_statuses.include?(params[:status])
|
|
776
|
+
|
|
777
|
+
# Use case: removing duplicates while preserving order
|
|
778
|
+
array = [3, 1, 2, 1, 3]
|
|
779
|
+
Set.new(array).to_a # => [3, 1, 2]
|
|
780
|
+
# Or simply:
|
|
781
|
+
array.uniq # => [3, 1, 2]
|
|
782
|
+
```
|
|
783
|
+
|
|
784
|
+
### SortedSet (Removed in Ruby 3.0+)
|
|
785
|
+
```ruby
|
|
786
|
+
# For sorted sets, use a sorted array or gem
|
|
787
|
+
# Or implement with binary search insertion
|
|
788
|
+
|
|
789
|
+
class SortedArray
|
|
790
|
+
def initialize
|
|
791
|
+
@array = []
|
|
792
|
+
end
|
|
793
|
+
|
|
794
|
+
def add(value)
|
|
795
|
+
index = @array.bsearch_index { |x| x >= value } || @array.length
|
|
796
|
+
@array.insert(index, value)
|
|
797
|
+
end
|
|
798
|
+
|
|
799
|
+
def include?(value)
|
|
800
|
+
@array.bsearch { |x| x <=> value }
|
|
801
|
+
end
|
|
802
|
+
|
|
803
|
+
def to_a
|
|
804
|
+
@array.dup
|
|
805
|
+
end
|
|
806
|
+
end
|
|
807
|
+
```
|
|
808
|
+
|
|
809
|
+
---
|
|
810
|
+
|
|
811
|
+
## Rails-Specific Optimizations
|
|
812
|
+
|
|
813
|
+
### Efficient Queries
|
|
814
|
+
```ruby
|
|
815
|
+
# Bad: N+1 query
|
|
816
|
+
users.each do |user|
|
|
817
|
+
puts user.orders.count # Query for each user
|
|
818
|
+
end
|
|
819
|
+
|
|
820
|
+
# Good: Eager loading
|
|
821
|
+
users = User.includes(:orders)
|
|
822
|
+
users.each do |user|
|
|
823
|
+
puts user.orders.size # No additional queries
|
|
824
|
+
end
|
|
825
|
+
|
|
826
|
+
# Better: Counter cache
|
|
827
|
+
# In migration
|
|
828
|
+
add_column :users, :orders_count, :integer, default: 0
|
|
829
|
+
User.reset_counters(user.id, :orders)
|
|
830
|
+
|
|
831
|
+
# In model
|
|
832
|
+
class Order < ApplicationRecord
|
|
833
|
+
belongs_to :user, counter_cache: true
|
|
834
|
+
end
|
|
835
|
+
|
|
836
|
+
# Now O(1) to get count
|
|
837
|
+
user.orders_count
|
|
838
|
+
```
|
|
839
|
+
|
|
840
|
+
### Batch Processing
|
|
841
|
+
```ruby
|
|
842
|
+
# Bad: Loads all records into memory
|
|
843
|
+
User.all.each { |user| process(user) }
|
|
844
|
+
|
|
845
|
+
# Good: Process in batches
|
|
846
|
+
User.find_each(batch_size: 1000) do |user|
|
|
847
|
+
process(user)
|
|
848
|
+
end
|
|
849
|
+
|
|
850
|
+
# With conditions
|
|
851
|
+
User.where(active: true).find_each do |user|
|
|
852
|
+
process(user)
|
|
853
|
+
end
|
|
854
|
+
|
|
855
|
+
# Parallel processing with batches
|
|
856
|
+
User.in_batches(of: 1000) do |batch|
|
|
857
|
+
batch.update_all(processed: true)
|
|
858
|
+
end
|
|
859
|
+
|
|
860
|
+
# For large exports
|
|
861
|
+
def export_users_csv
|
|
862
|
+
CSV.generate do |csv|
|
|
863
|
+
csv << %w[id email name]
|
|
864
|
+
User.find_each do |user|
|
|
865
|
+
csv << [user.id, user.email, user.name]
|
|
866
|
+
end
|
|
867
|
+
end
|
|
868
|
+
end
|
|
869
|
+
```
|
|
870
|
+
|
|
871
|
+
### Pluck vs Select
|
|
872
|
+
```ruby
|
|
873
|
+
# select loads ActiveRecord objects
|
|
874
|
+
emails = User.select(:email).map(&:email) # Creates User objects
|
|
875
|
+
|
|
876
|
+
# pluck returns just the values
|
|
877
|
+
emails = User.pluck(:email) # Just array of strings
|
|
878
|
+
|
|
879
|
+
# Multiple columns
|
|
880
|
+
data = User.pluck(:id, :email, :name)
|
|
881
|
+
# => [[1, "a@b.com", "Alice"], [2, "c@d.com", "Bob"]]
|
|
882
|
+
|
|
883
|
+
# For calculations
|
|
884
|
+
User.count # COUNT(*)
|
|
885
|
+
User.sum(:balance) # SUM(balance)
|
|
886
|
+
User.average(:age) # AVG(age)
|
|
887
|
+
User.maximum(:age) # MAX(age)
|
|
888
|
+
User.minimum(:created_at)# MIN(created_at)
|
|
889
|
+
```
|
|
890
|
+
|
|
891
|
+
### Index Optimization
|
|
892
|
+
```ruby
|
|
893
|
+
# Add indexes for:
|
|
894
|
+
# 1. Foreign keys
|
|
895
|
+
add_index :orders, :user_id
|
|
896
|
+
|
|
897
|
+
# 2. Columns used in WHERE clauses
|
|
898
|
+
add_index :users, :email
|
|
899
|
+
add_index :users, :status
|
|
900
|
+
|
|
901
|
+
# 3. Columns used in ORDER BY
|
|
902
|
+
add_index :posts, :created_at
|
|
903
|
+
|
|
904
|
+
# 4. Composite indexes for common query patterns
|
|
905
|
+
add_index :orders, [:user_id, :created_at]
|
|
906
|
+
add_index :products, [:category_id, :price]
|
|
907
|
+
|
|
908
|
+
# 5. Partial indexes for filtered queries
|
|
909
|
+
add_index :users, :email, where: "active = true"
|
|
910
|
+
|
|
911
|
+
# Check if query uses index
|
|
912
|
+
User.where(email: "test@example.com").explain
|
|
913
|
+
```
|
|
914
|
+
|
|
915
|
+
### Avoiding Common Performance Issues
|
|
916
|
+
```ruby
|
|
917
|
+
# Issue: String concatenation in loops
|
|
918
|
+
# Bad
|
|
919
|
+
result = ""
|
|
920
|
+
1000.times { |i| result += i.to_s }
|
|
921
|
+
|
|
922
|
+
# Good
|
|
923
|
+
result = []
|
|
924
|
+
1000.times { |i| result << i.to_s }
|
|
925
|
+
result.join
|
|
926
|
+
|
|
927
|
+
# Issue: Repeated calculations
|
|
928
|
+
# Bad
|
|
929
|
+
orders.each do |order|
|
|
930
|
+
tax_rate = TaxService.fetch_rate(order.region) # Called each time
|
|
931
|
+
order.update(tax: order.total * tax_rate)
|
|
932
|
+
end
|
|
933
|
+
|
|
934
|
+
# Good
|
|
935
|
+
rates = TaxService.fetch_all_rates
|
|
936
|
+
orders.each do |order|
|
|
937
|
+
order.update(tax: order.total * rates[order.region])
|
|
938
|
+
end
|
|
939
|
+
|
|
940
|
+
# Issue: Loading unnecessary data
|
|
941
|
+
# Bad
|
|
942
|
+
user = User.find(id) # Loads all columns
|
|
943
|
+
user.email
|
|
944
|
+
|
|
945
|
+
# Good
|
|
946
|
+
email = User.where(id: id).pick(:email) # Just one column, one value
|
|
947
|
+
|
|
948
|
+
# Issue: Serialization in hot paths
|
|
949
|
+
# Bad
|
|
950
|
+
class User < ApplicationRecord
|
|
951
|
+
serialize :preferences, coder: JSON # Parsing on every access
|
|
952
|
+
end
|
|
953
|
+
|
|
954
|
+
# Good: Use jsonb column (PostgreSQL) or separate table
|
|
955
|
+
```
|
|
956
|
+
|
|
957
|
+
### Algorithm Selection Guide
|
|
958
|
+
|
|
959
|
+
| Problem | Best Approach | Time |
|
|
960
|
+
|---------|--------------|------|
|
|
961
|
+
| Check if item exists | Hash/Set | O(1) |
|
|
962
|
+
| Find item by key | Hash | O(1) |
|
|
963
|
+
| Find item in sorted list | Binary search | O(log n) |
|
|
964
|
+
| Find item in unsorted list | Linear search | O(n) |
|
|
965
|
+
| Sort data | sort/sort_by | O(n log n) |
|
|
966
|
+
| Process all items | Each/map | O(n) |
|
|
967
|
+
| Find duplicates | Hash/Set | O(n) |
|
|
968
|
+
| Top K items | Partial sort | O(n log k) |
|
|
969
|
+
| Sliding window | Two pointers | O(n) |
|
|
970
|
+
| Tree/graph traversal | BFS/DFS | O(V + E) |
|