algorithm-discovery-engine 1.0.0__py3-none-any.whl

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.
ads/structures.py ADDED
@@ -0,0 +1,370 @@
1
+ """Regular Python data-structure tier: simple, readable implementations.
2
+
3
+ Mirror the Java / C++ / Rust ports. Each structure exposes the operation
4
+ contracts listed in ``catalog/problems.json``.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from collections import deque as _deque
10
+
11
+ _SENTINEL = -1
12
+
13
+
14
+ class Stack:
15
+ """LIFO stack backed by a list."""
16
+
17
+ __slots__ = ("_items",)
18
+
19
+ def __init__(self) -> None:
20
+ self._items: list[int] = []
21
+
22
+ def push(self, value: int) -> None:
23
+ self._items.append(value)
24
+
25
+ def pop(self) -> int:
26
+ return self._items.pop() if self._items else _SENTINEL
27
+
28
+ def peek(self) -> int:
29
+ return self._items[-1] if self._items else _SENTINEL
30
+
31
+ def is_empty(self) -> bool:
32
+ return not self._items
33
+
34
+ def size(self) -> int:
35
+ return len(self._items)
36
+
37
+
38
+ class Queue:
39
+ """FIFO queue backed by a deque."""
40
+
41
+ __slots__ = ("_items",)
42
+
43
+ def __init__(self) -> None:
44
+ self._items: _deque[int] = _deque()
45
+
46
+ def enqueue(self, value: int) -> None:
47
+ self._items.append(value)
48
+
49
+ def dequeue(self) -> int:
50
+ return self._items.popleft() if self._items else _SENTINEL
51
+
52
+ def peek(self) -> int:
53
+ return self._items[0] if self._items else _SENTINEL
54
+
55
+ def is_empty(self) -> bool:
56
+ return not self._items
57
+
58
+ def size(self) -> int:
59
+ return len(self._items)
60
+
61
+
62
+ class _Node:
63
+ __slots__ = ("next", "value")
64
+
65
+ def __init__(self, value: int) -> None:
66
+ self.value = value
67
+ self.next: _Node | None = None
68
+
69
+
70
+ class LinkedList:
71
+ """Singly linked list."""
72
+
73
+ __slots__ = ("_head", "_size", "_tail")
74
+
75
+ def __init__(self) -> None:
76
+ self._head: _Node | None = None
77
+ self._tail: _Node | None = None
78
+ self._size = 0
79
+
80
+ def append(self, value: int) -> None:
81
+ node = _Node(value)
82
+ if self._tail is None:
83
+ self._head = self._tail = node
84
+ else:
85
+ self._tail.next = node
86
+ self._tail = node
87
+ self._size += 1
88
+
89
+ def prepend(self, value: int) -> None:
90
+ node = _Node(value)
91
+ node.next = self._head
92
+ self._head = node
93
+ if self._tail is None:
94
+ self._tail = node
95
+ self._size += 1
96
+
97
+ def get(self, index: int) -> int:
98
+ if index < 0 or index >= self._size:
99
+ return _SENTINEL
100
+ node = self._head
101
+ for _ in range(index):
102
+ node = node.next # type: ignore[union-attr]
103
+ return node.value # type: ignore[union-attr]
104
+
105
+ def contains(self, value: int) -> bool:
106
+ node = self._head
107
+ while node is not None:
108
+ if node.value == value:
109
+ return True
110
+ node = node.next
111
+ return False
112
+
113
+ def remove(self, value: int) -> bool:
114
+ node, previous = self._head, None
115
+ while node is not None:
116
+ if node.value == value:
117
+ if previous is None:
118
+ self._head = node.next
119
+ else:
120
+ previous.next = node.next
121
+ if node is self._tail:
122
+ self._tail = previous
123
+ self._size -= 1
124
+ return True
125
+ previous, node = node, node.next
126
+ return False
127
+
128
+ def size(self) -> int:
129
+ return self._size
130
+
131
+ def to_list(self) -> list[int]:
132
+ out: list[int] = []
133
+ node = self._head
134
+ while node is not None:
135
+ out.append(node.value)
136
+ node = node.next
137
+ return out
138
+
139
+
140
+ class BST:
141
+ """Binary search tree."""
142
+
143
+ __slots__ = ("_root", "_size")
144
+
145
+ def __init__(self) -> None:
146
+ self._root: _BSTNode | None = None
147
+ self._size = 0
148
+
149
+ def insert(self, value: int) -> None:
150
+ if self._root is None:
151
+ self._root = _BSTNode(value)
152
+ self._size = 1
153
+ return
154
+ node = self._root
155
+ while True:
156
+ if value < node.value:
157
+ if node.left is None:
158
+ node.left = _BSTNode(value)
159
+ break
160
+ node = node.left
161
+ elif value > node.value:
162
+ if node.right is None:
163
+ node.right = _BSTNode(value)
164
+ break
165
+ node = node.right
166
+ else:
167
+ return
168
+ self._size += 1
169
+
170
+ def contains(self, value: int) -> bool:
171
+ node = self._root
172
+ while node is not None:
173
+ if value == node.value:
174
+ return True
175
+ node = node.left if value < node.value else node.right
176
+ return False
177
+
178
+ def min(self) -> int:
179
+ node = self._root
180
+ if node is None:
181
+ return _SENTINEL
182
+ while node.left is not None:
183
+ node = node.left
184
+ return node.value
185
+
186
+ def max(self) -> int:
187
+ node = self._root
188
+ if node is None:
189
+ return _SENTINEL
190
+ while node.right is not None:
191
+ node = node.right
192
+ return node.value
193
+
194
+ def height(self) -> int:
195
+ return _height(self._root)
196
+
197
+ def size(self) -> int:
198
+ return self._size
199
+
200
+ def in_order(self) -> list[int]:
201
+ out: list[int] = []
202
+ _in_order(self._root, out)
203
+ return out
204
+
205
+ def remove(self, value: int) -> bool:
206
+ found = self._contains(self._root, value)
207
+ if not found:
208
+ return False
209
+ self._root = _remove(self._root, value)
210
+ self._size -= 1
211
+ return True
212
+
213
+ @staticmethod
214
+ def _contains(node: _BSTNode | None, value: int) -> bool:
215
+ if node is None:
216
+ return False
217
+ if value == node.value:
218
+ return True
219
+ return BST._contains(node.left if value < node.value else node.right, value)
220
+
221
+
222
+ class _BSTNode:
223
+ __slots__ = ("left", "right", "value")
224
+
225
+ def __init__(self, value: int) -> None:
226
+ self.value = value
227
+ self.left: _BSTNode | None = None
228
+ self.right: _BSTNode | None = None
229
+
230
+
231
+ def _height(node: _BSTNode | None) -> int:
232
+ if node is None:
233
+ return -1
234
+ return 1 + max(_height(node.left), _height(node.right))
235
+
236
+
237
+ def _in_order(node: _BSTNode | None, out: list[int]) -> None:
238
+ if node is None:
239
+ return
240
+ _in_order(node.left, out)
241
+ out.append(node.value)
242
+ _in_order(node.right, out)
243
+
244
+
245
+ def _remove(node: _BSTNode | None, value: int) -> _BSTNode | None:
246
+ if node is None:
247
+ return None
248
+ if value < node.value:
249
+ node.left = _remove(node.left, value)
250
+ elif value > node.value:
251
+ node.right = _remove(node.right, value)
252
+ else:
253
+ if node.left is None:
254
+ return node.right
255
+ if node.right is None:
256
+ return node.left
257
+ successor = node.right
258
+ while successor.left is not None:
259
+ successor = successor.left
260
+ node.value = successor.value
261
+ node.right = _remove(node.right, successor.value)
262
+ return node
263
+
264
+
265
+ class Trie:
266
+ """Prefix trie storing unique words."""
267
+
268
+ __slots__ = ("_root", "_size")
269
+
270
+ def __init__(self) -> None:
271
+ self._root: _TrieNode = _TrieNode()
272
+ self._size = 0
273
+
274
+ def insert(self, word: str) -> None:
275
+ node = self._root
276
+ for ch in word:
277
+ if ch not in node.children:
278
+ node.children[ch] = _TrieNode()
279
+ node = node.children[ch]
280
+ if not node.terminal:
281
+ node.terminal = True
282
+ self._size += 1
283
+
284
+ def search(self, word: str) -> bool:
285
+ node = self._root
286
+ for ch in word:
287
+ if ch not in node.children:
288
+ return False
289
+ node = node.children[ch]
290
+ return node.terminal
291
+
292
+ def starts_with(self, prefix: str) -> bool:
293
+ node = self._root
294
+ for ch in prefix:
295
+ if ch not in node.children:
296
+ return False
297
+ node = node.children[ch]
298
+ return True
299
+
300
+ def size(self) -> int:
301
+ return self._size
302
+
303
+
304
+ class _TrieNode:
305
+ __slots__ = ("children", "terminal")
306
+
307
+ def __init__(self) -> None:
308
+ self.children: dict[str, _TrieNode] = {}
309
+ self.terminal = False
310
+
311
+
312
+ class MinHeap:
313
+ """Binary min-heap over a list."""
314
+
315
+ __slots__ = ("_items",)
316
+
317
+ def __init__(self) -> None:
318
+ self._items: list[int] = []
319
+
320
+ def push(self, value: int) -> None:
321
+ self._items.append(value)
322
+ self._sift_up(len(self._items) - 1)
323
+
324
+ def pop(self) -> int:
325
+ if not self._items:
326
+ return _SENTINEL
327
+ top = self._items[0]
328
+ last = self._items.pop()
329
+ if self._items:
330
+ self._items[0] = last
331
+ self._sift_down(0)
332
+ return top
333
+
334
+ def peek(self) -> int:
335
+ return self._items[0] if self._items else _SENTINEL
336
+
337
+ def is_empty(self) -> bool:
338
+ return not self._items
339
+
340
+ def size(self) -> int:
341
+ return len(self._items)
342
+
343
+ def _sift_up(self, index: int) -> None:
344
+ while index > 0:
345
+ parent = (index - 1) // 2
346
+ if self._items[parent] <= self._items[index]:
347
+ return
348
+ self._items[parent], self._items[index] = (
349
+ self._items[index],
350
+ self._items[parent],
351
+ )
352
+ index = parent
353
+
354
+ def _sift_down(self, index: int) -> None:
355
+ size = len(self._items)
356
+ while True:
357
+ left = 2 * index + 1
358
+ right = left + 1
359
+ smallest = index
360
+ if left < size and self._items[left] < self._items[smallest]:
361
+ smallest = left
362
+ if right < size and self._items[right] < self._items[smallest]:
363
+ smallest = right
364
+ if smallest == index:
365
+ return
366
+ self._items[index], self._items[smallest] = (
367
+ self._items[smallest],
368
+ self._items[index],
369
+ )
370
+ index = smallest