algonest 0.1.0__tar.gz
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.
- algonest-0.1.0/LICENSE +21 -0
- algonest-0.1.0/PKG-INFO +77 -0
- algonest-0.1.0/README.md +48 -0
- algonest-0.1.0/algonest/__init__.py +223 -0
- algonest-0.1.0/algonest/arrays/__init__.py +21 -0
- algonest-0.1.0/algonest/arrays/dutch_flag.py +92 -0
- algonest-0.1.0/algonest/arrays/kadane.py +42 -0
- algonest-0.1.0/algonest/arrays/prefix_sum.py +115 -0
- algonest-0.1.0/algonest/arrays/sliding_window.py +90 -0
- algonest-0.1.0/algonest/arrays/two_pointers.py +119 -0
- algonest-0.1.0/algonest/dynamic_programming/__init__.py +19 -0
- algonest-0.1.0/algonest/dynamic_programming/coin_change.py +26 -0
- algonest-0.1.0/algonest/dynamic_programming/edit_distance.py +26 -0
- algonest-0.1.0/algonest/dynamic_programming/knapsack.py +23 -0
- algonest-0.1.0/algonest/dynamic_programming/lcs.py +17 -0
- algonest-0.1.0/algonest/dynamic_programming/lis.py +26 -0
- algonest-0.1.0/algonest/dynamic_programming/matrix_chain.py +27 -0
- algonest-0.1.0/algonest/graphs/__init__.py +27 -0
- algonest-0.1.0/algonest/graphs/bellman_ford.py +30 -0
- algonest-0.1.0/algonest/graphs/bfs.py +53 -0
- algonest-0.1.0/algonest/graphs/dfs.py +65 -0
- algonest-0.1.0/algonest/graphs/dijkstra.py +29 -0
- algonest-0.1.0/algonest/graphs/dsu.py +32 -0
- algonest-0.1.0/algonest/graphs/floyd_warshall.py +17 -0
- algonest-0.1.0/algonest/graphs/kruskal.py +21 -0
- algonest-0.1.0/algonest/graphs/prim.py +28 -0
- algonest-0.1.0/algonest/graphs/topological_sort.py +52 -0
- algonest-0.1.0/algonest/heap/__init__.py +7 -0
- algonest-0.1.0/algonest/heap/max_heap.py +95 -0
- algonest-0.1.0/algonest/heap/min_heap.py +95 -0
- algonest-0.1.0/algonest/heap/priority_queue.py +128 -0
- algonest-0.1.0/algonest/linked_list/__init__.py +14 -0
- algonest-0.1.0/algonest/linked_list/circular.py +120 -0
- algonest-0.1.0/algonest/linked_list/doubly.py +98 -0
- algonest-0.1.0/algonest/linked_list/node.py +32 -0
- algonest-0.1.0/algonest/linked_list/singly.py +121 -0
- algonest-0.1.0/algonest/math/__init__.py +31 -0
- algonest-0.1.0/algonest/math/bit_manipulation.py +33 -0
- algonest-0.1.0/algonest/math/fast_power.py +16 -0
- algonest-0.1.0/algonest/math/gcd_lcm.py +32 -0
- algonest-0.1.0/algonest/math/modular_arithmetic.py +46 -0
- algonest-0.1.0/algonest/math/prime_sieve.py +47 -0
- algonest-0.1.0/algonest/search/__init__.py +19 -0
- algonest-0.1.0/algonest/search/binary_search.py +223 -0
- algonest-0.1.0/algonest/sort/__init__.py +23 -0
- algonest-0.1.0/algonest/sort/sorting.py +320 -0
- algonest-0.1.0/algonest/stack_queue/__init__.py +14 -0
- algonest-0.1.0/algonest/stack_queue/deque.py +83 -0
- algonest-0.1.0/algonest/stack_queue/monotonic_stack.py +84 -0
- algonest-0.1.0/algonest/stack_queue/queue.py +69 -0
- algonest-0.1.0/algonest/stack_queue/stack.py +68 -0
- algonest-0.1.0/algonest/strings/__init__.py +18 -0
- algonest-0.1.0/algonest/strings/anagram.py +54 -0
- algonest-0.1.0/algonest/strings/kmp.py +39 -0
- algonest-0.1.0/algonest/strings/rabin_karp.py +31 -0
- algonest-0.1.0/algonest/strings/trie.py +59 -0
- algonest-0.1.0/algonest/strings/z_algorithm.py +34 -0
- algonest-0.1.0/algonest/trees/__init__.py +22 -0
- algonest-0.1.0/algonest/trees/avl_tree.py +87 -0
- algonest-0.1.0/algonest/trees/binary_tree.py +109 -0
- algonest-0.1.0/algonest/trees/bst.py +150 -0
- algonest-0.1.0/algonest/trees/fenwick_tree.py +43 -0
- algonest-0.1.0/algonest/trees/node.py +19 -0
- algonest-0.1.0/algonest/trees/segment_tree.py +101 -0
- algonest-0.1.0/algonest/trees/traversals.py +104 -0
- algonest-0.1.0/algonest/utils/__init__.py +20 -0
- algonest-0.1.0/algonest/utils/debug.py +63 -0
- algonest-0.1.0/algonest/utils/fast_io.py +67 -0
- algonest-0.1.0/algonest/utils/test_runner.py +59 -0
- algonest-0.1.0/algonest/utils/type_helpers.py +6 -0
- algonest-0.1.0/algonest/utils/validators.py +36 -0
- algonest-0.1.0/algonest.egg-info/PKG-INFO +77 -0
- algonest-0.1.0/algonest.egg-info/SOURCES.txt +76 -0
- algonest-0.1.0/algonest.egg-info/dependency_links.txt +1 -0
- algonest-0.1.0/algonest.egg-info/requires.txt +4 -0
- algonest-0.1.0/algonest.egg-info/top_level.txt +1 -0
- algonest-0.1.0/pyproject.toml +41 -0
- algonest-0.1.0/setup.cfg +4 -0
algonest-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 dsa-kit contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
algonest-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: algonest
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Lightweight DSA utilities for Python
|
|
5
|
+
Author: Varun K S
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/your-org/algonest
|
|
8
|
+
Project-URL: Repository, https://github.com/your-org/algonest
|
|
9
|
+
Project-URL: Issues, https://github.com/your-org/algonest/issues
|
|
10
|
+
Keywords: dsa,algorithms,data-structures,python,interview
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
21
|
+
Classifier: Topic :: Education
|
|
22
|
+
Requires-Python: >=3.8
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
27
|
+
Requires-Dist: flake8>=6.0; extra == "dev"
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# AlgoNest
|
|
31
|
+
|
|
32
|
+
algonest is a clean, reusable Python DSA utility package focused on production-ready implementations of core algorithmic patterns.
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install algonest
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Included Modules
|
|
41
|
+
|
|
42
|
+
- `algonest.search.binary_search`: `lower_bound`, `upper_bound`, `binary_search`
|
|
43
|
+
- `algonest.arrays.sliding_window`: `max_sum_subarray_k`, `longest_unique_substring`
|
|
44
|
+
- `algonest.sort.sorting`: classical sorting algorithms
|
|
45
|
+
- `algonest.linked_list`: linked list data structures
|
|
46
|
+
- `algonest.stack_queue`: stack, queue, deque, monotonic stack utilities
|
|
47
|
+
- `algonest.heap`: min heap, max heap, priority queue
|
|
48
|
+
- `algonest.trees`: binary trees, BST/AVL, traversals, segment/fenwick trees
|
|
49
|
+
- `algonest.graphs`: traversal, shortest path, MST, DSU, topological sorting
|
|
50
|
+
- `algonest.dynamic_programming`: knapsack, LCS/LIS, coin change, MCM, edit distance
|
|
51
|
+
- `algonest.strings`: KMP, Rabin-Karp, Z algorithm, trie, anagram utilities
|
|
52
|
+
- `algonest.math`: gcd/lcm, prime utilities, modular arithmetic, bit tricks
|
|
53
|
+
- `algonest.utils`: validators and shared type helper aliases
|
|
54
|
+
|
|
55
|
+
## Quick Start
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from algonest import (
|
|
59
|
+
binary_search,
|
|
60
|
+
longest_unique_substring,
|
|
61
|
+
lower_bound,
|
|
62
|
+
max_sum_subarray_k,
|
|
63
|
+
upper_bound,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
idx = lower_bound([1, 2, 2, 4], 2)
|
|
67
|
+
hi = upper_bound([1, 2, 2, 4], 2)
|
|
68
|
+
pos = binary_search([1, 3, 5, 7], 5)
|
|
69
|
+
best = max_sum_subarray_k([2, 1, 5, 1, 3, 2], 3)
|
|
70
|
+
size = longest_unique_substring("abcabcbb")
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Testing
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
python -m pytest -q tests
|
|
77
|
+
```
|
algonest-0.1.0/README.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# AlgoNest
|
|
2
|
+
|
|
3
|
+
algonest is a clean, reusable Python DSA utility package focused on production-ready implementations of core algorithmic patterns.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install algonest
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Included Modules
|
|
12
|
+
|
|
13
|
+
- `algonest.search.binary_search`: `lower_bound`, `upper_bound`, `binary_search`
|
|
14
|
+
- `algonest.arrays.sliding_window`: `max_sum_subarray_k`, `longest_unique_substring`
|
|
15
|
+
- `algonest.sort.sorting`: classical sorting algorithms
|
|
16
|
+
- `algonest.linked_list`: linked list data structures
|
|
17
|
+
- `algonest.stack_queue`: stack, queue, deque, monotonic stack utilities
|
|
18
|
+
- `algonest.heap`: min heap, max heap, priority queue
|
|
19
|
+
- `algonest.trees`: binary trees, BST/AVL, traversals, segment/fenwick trees
|
|
20
|
+
- `algonest.graphs`: traversal, shortest path, MST, DSU, topological sorting
|
|
21
|
+
- `algonest.dynamic_programming`: knapsack, LCS/LIS, coin change, MCM, edit distance
|
|
22
|
+
- `algonest.strings`: KMP, Rabin-Karp, Z algorithm, trie, anagram utilities
|
|
23
|
+
- `algonest.math`: gcd/lcm, prime utilities, modular arithmetic, bit tricks
|
|
24
|
+
- `algonest.utils`: validators and shared type helper aliases
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from algonest import (
|
|
30
|
+
binary_search,
|
|
31
|
+
longest_unique_substring,
|
|
32
|
+
lower_bound,
|
|
33
|
+
max_sum_subarray_k,
|
|
34
|
+
upper_bound,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
idx = lower_bound([1, 2, 2, 4], 2)
|
|
38
|
+
hi = upper_bound([1, 2, 2, 4], 2)
|
|
39
|
+
pos = binary_search([1, 3, 5, 7], 5)
|
|
40
|
+
best = max_sum_subarray_k([2, 1, 5, 1, 3, 2], 3)
|
|
41
|
+
size = longest_unique_substring("abcabcbb")
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Testing
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
python -m pytest -q tests
|
|
48
|
+
```
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"""Public API for algonest Phase 5."""
|
|
2
|
+
|
|
3
|
+
from algonest.arrays import (
|
|
4
|
+
container_with_water,
|
|
5
|
+
longest_unique_substring,
|
|
6
|
+
max_subarray_sum,
|
|
7
|
+
max_sum_subarray_k,
|
|
8
|
+
partition_by_pivot,
|
|
9
|
+
prefix_sum,
|
|
10
|
+
range_sum,
|
|
11
|
+
remove_duplicates,
|
|
12
|
+
sort_three_values,
|
|
13
|
+
subarray_sum_equals_k,
|
|
14
|
+
two_sum_sorted,
|
|
15
|
+
)
|
|
16
|
+
from algonest.search import (
|
|
17
|
+
binary_search,
|
|
18
|
+
jump_search,
|
|
19
|
+
linear_search,
|
|
20
|
+
lower_bound,
|
|
21
|
+
ternary_search,
|
|
22
|
+
upper_bound,
|
|
23
|
+
)
|
|
24
|
+
from algonest.heap import MaxHeap, MinHeap, PriorityQueue
|
|
25
|
+
from algonest.linked_list import (
|
|
26
|
+
CircularLinkedList,
|
|
27
|
+
DoublyLinkedList,
|
|
28
|
+
DoublyListNode,
|
|
29
|
+
ListNode,
|
|
30
|
+
SinglyLinkedList,
|
|
31
|
+
)
|
|
32
|
+
from algonest.sort import (
|
|
33
|
+
bubble_sort,
|
|
34
|
+
counting_sort,
|
|
35
|
+
heap_sort,
|
|
36
|
+
insertion_sort,
|
|
37
|
+
merge_sort,
|
|
38
|
+
quick_sort,
|
|
39
|
+
radix_sort,
|
|
40
|
+
selection_sort,
|
|
41
|
+
)
|
|
42
|
+
from algonest.stack_queue import (
|
|
43
|
+
DequeDS,
|
|
44
|
+
Queue,
|
|
45
|
+
Stack,
|
|
46
|
+
largest_rectangle_in_histogram,
|
|
47
|
+
next_greater_element,
|
|
48
|
+
)
|
|
49
|
+
from algonest.dynamic_programming import (
|
|
50
|
+
coin_change_ways,
|
|
51
|
+
edit_distance,
|
|
52
|
+
knapsack_01,
|
|
53
|
+
lcs_length,
|
|
54
|
+
lis_length,
|
|
55
|
+
matrix_chain_order,
|
|
56
|
+
min_coins,
|
|
57
|
+
unbounded_knapsack,
|
|
58
|
+
)
|
|
59
|
+
from algonest.graphs import (
|
|
60
|
+
DSU,
|
|
61
|
+
bellman_ford,
|
|
62
|
+
bfs_traversal,
|
|
63
|
+
connected_components,
|
|
64
|
+
dfs_topological_sort,
|
|
65
|
+
dfs_traversal,
|
|
66
|
+
dijkstra_shortest_paths,
|
|
67
|
+
floyd_warshall,
|
|
68
|
+
has_cycle_undirected,
|
|
69
|
+
kahn_topological_sort,
|
|
70
|
+
kruskal_mst,
|
|
71
|
+
prim_mst,
|
|
72
|
+
shortest_path_unweighted,
|
|
73
|
+
)
|
|
74
|
+
from algonest.trees import (
|
|
75
|
+
AVLTree,
|
|
76
|
+
BST,
|
|
77
|
+
BinaryTree,
|
|
78
|
+
FenwickTree,
|
|
79
|
+
SegmentTree,
|
|
80
|
+
TreeNode,
|
|
81
|
+
inorder,
|
|
82
|
+
level_order,
|
|
83
|
+
postorder,
|
|
84
|
+
preorder,
|
|
85
|
+
)
|
|
86
|
+
from algonest.strings import (
|
|
87
|
+
Trie,
|
|
88
|
+
find_all_anagrams,
|
|
89
|
+
group_anagrams,
|
|
90
|
+
is_anagram,
|
|
91
|
+
kmp_search,
|
|
92
|
+
rabin_karp_search,
|
|
93
|
+
z_array,
|
|
94
|
+
z_search,
|
|
95
|
+
)
|
|
96
|
+
from algonest.math import (
|
|
97
|
+
chinese_remainder_theorem,
|
|
98
|
+
clear_bit,
|
|
99
|
+
count_bits,
|
|
100
|
+
extended_gcd,
|
|
101
|
+
fast_power,
|
|
102
|
+
gcd,
|
|
103
|
+
is_power_of_two,
|
|
104
|
+
is_prime,
|
|
105
|
+
lcm,
|
|
106
|
+
mod_exp,
|
|
107
|
+
mod_inverse,
|
|
108
|
+
prime_factors,
|
|
109
|
+
set_bit,
|
|
110
|
+
sieve_of_eratosthenes,
|
|
111
|
+
xor_trick,
|
|
112
|
+
)
|
|
113
|
+
from algonest.utils import (
|
|
114
|
+
assert_sorted,
|
|
115
|
+
build_pytest_command,
|
|
116
|
+
read_ints_from_text,
|
|
117
|
+
run_tests,
|
|
118
|
+
time_function,
|
|
119
|
+
validate_iterable,
|
|
120
|
+
write_lines,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
__all__ = [
|
|
124
|
+
"lower_bound",
|
|
125
|
+
"upper_bound",
|
|
126
|
+
"binary_search",
|
|
127
|
+
"linear_search",
|
|
128
|
+
"ternary_search",
|
|
129
|
+
"jump_search",
|
|
130
|
+
"max_sum_subarray_k",
|
|
131
|
+
"longest_unique_substring",
|
|
132
|
+
"two_sum_sorted",
|
|
133
|
+
"remove_duplicates",
|
|
134
|
+
"container_with_water",
|
|
135
|
+
"prefix_sum",
|
|
136
|
+
"range_sum",
|
|
137
|
+
"subarray_sum_equals_k",
|
|
138
|
+
"max_subarray_sum",
|
|
139
|
+
"sort_three_values",
|
|
140
|
+
"partition_by_pivot",
|
|
141
|
+
"bubble_sort",
|
|
142
|
+
"selection_sort",
|
|
143
|
+
"insertion_sort",
|
|
144
|
+
"merge_sort",
|
|
145
|
+
"quick_sort",
|
|
146
|
+
"heap_sort",
|
|
147
|
+
"counting_sort",
|
|
148
|
+
"radix_sort",
|
|
149
|
+
"ListNode",
|
|
150
|
+
"DoublyListNode",
|
|
151
|
+
"SinglyLinkedList",
|
|
152
|
+
"DoublyLinkedList",
|
|
153
|
+
"CircularLinkedList",
|
|
154
|
+
"Stack",
|
|
155
|
+
"Queue",
|
|
156
|
+
"DequeDS",
|
|
157
|
+
"next_greater_element",
|
|
158
|
+
"largest_rectangle_in_histogram",
|
|
159
|
+
"MinHeap",
|
|
160
|
+
"MaxHeap",
|
|
161
|
+
"PriorityQueue",
|
|
162
|
+
"TreeNode",
|
|
163
|
+
"BinaryTree",
|
|
164
|
+
"BST",
|
|
165
|
+
"inorder",
|
|
166
|
+
"preorder",
|
|
167
|
+
"postorder",
|
|
168
|
+
"level_order",
|
|
169
|
+
"AVLTree",
|
|
170
|
+
"SegmentTree",
|
|
171
|
+
"FenwickTree",
|
|
172
|
+
"bfs_traversal",
|
|
173
|
+
"shortest_path_unweighted",
|
|
174
|
+
"dfs_traversal",
|
|
175
|
+
"connected_components",
|
|
176
|
+
"has_cycle_undirected",
|
|
177
|
+
"dijkstra_shortest_paths",
|
|
178
|
+
"bellman_ford",
|
|
179
|
+
"floyd_warshall",
|
|
180
|
+
"kahn_topological_sort",
|
|
181
|
+
"dfs_topological_sort",
|
|
182
|
+
"kruskal_mst",
|
|
183
|
+
"prim_mst",
|
|
184
|
+
"DSU",
|
|
185
|
+
"knapsack_01",
|
|
186
|
+
"unbounded_knapsack",
|
|
187
|
+
"lcs_length",
|
|
188
|
+
"lis_length",
|
|
189
|
+
"min_coins",
|
|
190
|
+
"coin_change_ways",
|
|
191
|
+
"matrix_chain_order",
|
|
192
|
+
"edit_distance",
|
|
193
|
+
"kmp_search",
|
|
194
|
+
"rabin_karp_search",
|
|
195
|
+
"z_array",
|
|
196
|
+
"z_search",
|
|
197
|
+
"Trie",
|
|
198
|
+
"group_anagrams",
|
|
199
|
+
"is_anagram",
|
|
200
|
+
"find_all_anagrams",
|
|
201
|
+
"gcd",
|
|
202
|
+
"lcm",
|
|
203
|
+
"extended_gcd",
|
|
204
|
+
"sieve_of_eratosthenes",
|
|
205
|
+
"is_prime",
|
|
206
|
+
"prime_factors",
|
|
207
|
+
"mod_exp",
|
|
208
|
+
"mod_inverse",
|
|
209
|
+
"chinese_remainder_theorem",
|
|
210
|
+
"fast_power",
|
|
211
|
+
"count_bits",
|
|
212
|
+
"is_power_of_two",
|
|
213
|
+
"set_bit",
|
|
214
|
+
"clear_bit",
|
|
215
|
+
"xor_trick",
|
|
216
|
+
"validate_iterable",
|
|
217
|
+
"read_ints_from_text",
|
|
218
|
+
"write_lines",
|
|
219
|
+
"time_function",
|
|
220
|
+
"assert_sorted",
|
|
221
|
+
"build_pytest_command",
|
|
222
|
+
"run_tests",
|
|
223
|
+
]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Array algorithms package."""
|
|
2
|
+
|
|
3
|
+
from algonest.arrays.dutch_flag import partition_by_pivot, sort_three_values
|
|
4
|
+
from algonest.arrays.kadane import max_subarray_sum
|
|
5
|
+
from algonest.arrays.prefix_sum import prefix_sum, range_sum, subarray_sum_equals_k
|
|
6
|
+
from algonest.arrays.sliding_window import longest_unique_substring, max_sum_subarray_k
|
|
7
|
+
from algonest.arrays.two_pointers import container_with_water, remove_duplicates, two_sum_sorted
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"max_sum_subarray_k",
|
|
11
|
+
"longest_unique_substring",
|
|
12
|
+
"two_sum_sorted",
|
|
13
|
+
"remove_duplicates",
|
|
14
|
+
"container_with_water",
|
|
15
|
+
"prefix_sum",
|
|
16
|
+
"range_sum",
|
|
17
|
+
"subarray_sum_equals_k",
|
|
18
|
+
"max_subarray_sum",
|
|
19
|
+
"sort_three_values",
|
|
20
|
+
"partition_by_pivot",
|
|
21
|
+
]
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""Dutch flag partitioning algorithms."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Iterable, List
|
|
4
|
+
|
|
5
|
+
from algonest.utils import _validate_iterable
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def sort_three_values(
|
|
9
|
+
arr: Iterable[Any],
|
|
10
|
+
low_value: Any,
|
|
11
|
+
mid_value: Any,
|
|
12
|
+
high_value: Any,
|
|
13
|
+
) -> List[Any]:
|
|
14
|
+
"""Return values sorted by low/mid/high categories in one pass.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
arr (Iterable[Any]): Iterable containing only three category values.
|
|
18
|
+
low_value (Any): Category that should appear first.
|
|
19
|
+
mid_value (Any): Category that should appear second.
|
|
20
|
+
high_value (Any): Category that should appear third.
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
List[Any]: Newly sorted list by category order.
|
|
24
|
+
|
|
25
|
+
Raises:
|
|
26
|
+
TypeError: If arr is not iterable.
|
|
27
|
+
ValueError: If arr contains values outside the three categories.
|
|
28
|
+
|
|
29
|
+
Time Complexity: O(n)
|
|
30
|
+
Space Complexity: O(n)
|
|
31
|
+
|
|
32
|
+
Example:
|
|
33
|
+
>>> sort_three_values([2, 0, 1, 2, 1, 0], 0, 1, 2)
|
|
34
|
+
[0, 0, 1, 1, 2, 2]
|
|
35
|
+
"""
|
|
36
|
+
values = _validate_iterable(arr)
|
|
37
|
+
allowed = {low_value, mid_value, high_value}
|
|
38
|
+
for value in values:
|
|
39
|
+
if value not in allowed:
|
|
40
|
+
raise ValueError("arr must contain only the three provided values")
|
|
41
|
+
|
|
42
|
+
out = values[:]
|
|
43
|
+
low = 0
|
|
44
|
+
mid = 0
|
|
45
|
+
high = len(out) - 1
|
|
46
|
+
while mid <= high:
|
|
47
|
+
if out[mid] == low_value:
|
|
48
|
+
out[low], out[mid] = out[mid], out[low]
|
|
49
|
+
low += 1
|
|
50
|
+
mid += 1
|
|
51
|
+
elif out[mid] == mid_value:
|
|
52
|
+
mid += 1
|
|
53
|
+
else:
|
|
54
|
+
out[mid], out[high] = out[high], out[mid]
|
|
55
|
+
high -= 1
|
|
56
|
+
return out
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def partition_by_pivot(arr: Iterable[Any], pivot: Any) -> List[Any]:
|
|
60
|
+
"""Return values partitioned into < pivot, == pivot, > pivot.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
arr (Iterable[Any]): Iterable input values.
|
|
64
|
+
pivot (Any): Pivot for partitioning.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
List[Any]: Partitioned list.
|
|
68
|
+
|
|
69
|
+
Raises:
|
|
70
|
+
TypeError: If arr is not iterable.
|
|
71
|
+
|
|
72
|
+
Time Complexity: O(n)
|
|
73
|
+
Space Complexity: O(n)
|
|
74
|
+
|
|
75
|
+
Example:
|
|
76
|
+
>>> partition_by_pivot([3, 5, 2, 5, 1], 3)
|
|
77
|
+
[2, 1, 3, 5, 5]
|
|
78
|
+
"""
|
|
79
|
+
values = _validate_iterable(arr)
|
|
80
|
+
lower: List[Any] = []
|
|
81
|
+
equal: List[Any] = []
|
|
82
|
+
higher: List[Any] = []
|
|
83
|
+
|
|
84
|
+
for value in values:
|
|
85
|
+
if value < pivot:
|
|
86
|
+
lower.append(value)
|
|
87
|
+
elif value == pivot:
|
|
88
|
+
equal.append(value)
|
|
89
|
+
else:
|
|
90
|
+
higher.append(value)
|
|
91
|
+
|
|
92
|
+
return lower + equal + higher
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Kadane algorithm for maximum subarray sum."""
|
|
2
|
+
|
|
3
|
+
from numbers import Real
|
|
4
|
+
from typing import Iterable
|
|
5
|
+
|
|
6
|
+
from algonest.utils import _validate_iterable
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def max_subarray_sum(arr: Iterable[Real]) -> Real:
|
|
10
|
+
"""Return the maximum sum among all contiguous subarrays.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
arr (Iterable[Real]): Iterable of numeric values.
|
|
14
|
+
|
|
15
|
+
Returns:
|
|
16
|
+
Real: Maximum contiguous subarray sum.
|
|
17
|
+
|
|
18
|
+
Raises:
|
|
19
|
+
TypeError: If arr is not iterable or contains non-numeric values.
|
|
20
|
+
ValueError: If input is empty.
|
|
21
|
+
|
|
22
|
+
Time Complexity: O(n)
|
|
23
|
+
Space Complexity: O(n)
|
|
24
|
+
|
|
25
|
+
Example:
|
|
26
|
+
>>> max_subarray_sum([-2, 1, -3, 4, -1, 2, 1, -5, 4])
|
|
27
|
+
6
|
|
28
|
+
"""
|
|
29
|
+
values = _validate_iterable(arr)
|
|
30
|
+
if not values:
|
|
31
|
+
raise ValueError("arr cannot be empty")
|
|
32
|
+
|
|
33
|
+
for value in values:
|
|
34
|
+
if not isinstance(value, Real) or isinstance(value, bool):
|
|
35
|
+
raise TypeError("All elements in arr must be numeric")
|
|
36
|
+
|
|
37
|
+
current = values[0]
|
|
38
|
+
best = values[0]
|
|
39
|
+
for value in values[1:]:
|
|
40
|
+
current = max(value, current + value)
|
|
41
|
+
best = max(best, current)
|
|
42
|
+
return best
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""Prefix-sum based array algorithms."""
|
|
2
|
+
|
|
3
|
+
from numbers import Real
|
|
4
|
+
from typing import Any, Iterable, List
|
|
5
|
+
|
|
6
|
+
from algonest.utils import _validate_iterable
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def prefix_sum(arr: Iterable[Real]) -> List[Real]:
|
|
10
|
+
"""Return prefix sums for numeric iterable input.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
arr (Iterable[Real]): Iterable of numeric values.
|
|
14
|
+
|
|
15
|
+
Returns:
|
|
16
|
+
List[Real]: Prefix sums where out[i] = sum(arr[0:i+1]).
|
|
17
|
+
|
|
18
|
+
Raises:
|
|
19
|
+
TypeError: If arr is not iterable or contains non-numeric values.
|
|
20
|
+
|
|
21
|
+
Time Complexity: O(n)
|
|
22
|
+
Space Complexity: O(n)
|
|
23
|
+
|
|
24
|
+
Example:
|
|
25
|
+
>>> prefix_sum([3, 5, 2, 7])
|
|
26
|
+
[3, 8, 10, 17]
|
|
27
|
+
"""
|
|
28
|
+
values = _validate_iterable(arr)
|
|
29
|
+
out: List[Real] = []
|
|
30
|
+
running: Real = 0
|
|
31
|
+
|
|
32
|
+
for value in values:
|
|
33
|
+
if not isinstance(value, Real) or isinstance(value, bool):
|
|
34
|
+
raise TypeError("All elements in arr must be numeric")
|
|
35
|
+
running += value
|
|
36
|
+
out.append(running)
|
|
37
|
+
return out
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def range_sum(prefix: Iterable[Real], left: int, right: int) -> Real:
|
|
41
|
+
"""Return inclusive sum from left to right using prefix sums.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
prefix (Iterable[Real]): Prefix-sum iterable.
|
|
45
|
+
left (int): Left index, inclusive.
|
|
46
|
+
right (int): Right index, inclusive.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
Real: Sum over [left, right].
|
|
50
|
+
|
|
51
|
+
Raises:
|
|
52
|
+
TypeError: If prefix is not iterable or bounds are not integers.
|
|
53
|
+
ValueError: If prefix is empty or left > right.
|
|
54
|
+
IndexError: If bounds are out of range.
|
|
55
|
+
|
|
56
|
+
Time Complexity: O(1)
|
|
57
|
+
Space Complexity: O(n)
|
|
58
|
+
|
|
59
|
+
Example:
|
|
60
|
+
>>> p = prefix_sum([3, 5, 2, 7])
|
|
61
|
+
>>> range_sum(p, 1, 3)
|
|
62
|
+
14
|
|
63
|
+
"""
|
|
64
|
+
values = _validate_iterable(prefix)
|
|
65
|
+
if not values:
|
|
66
|
+
raise ValueError("prefix cannot be empty")
|
|
67
|
+
if not isinstance(left, int) or isinstance(left, bool):
|
|
68
|
+
raise TypeError("left must be an integer")
|
|
69
|
+
if not isinstance(right, int) or isinstance(right, bool):
|
|
70
|
+
raise TypeError("right must be an integer")
|
|
71
|
+
if left > right:
|
|
72
|
+
raise ValueError("left cannot be greater than right")
|
|
73
|
+
if left < 0 or right < 0 or left >= len(values) or right >= len(values):
|
|
74
|
+
raise IndexError("left and right must be valid indices")
|
|
75
|
+
|
|
76
|
+
return values[right] if left == 0 else values[right] - values[left - 1]
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def subarray_sum_equals_k(arr: Iterable[Real], k: Real) -> int:
|
|
80
|
+
"""Return count of contiguous subarrays with sum exactly equal to k.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
arr (Iterable[Real]): Iterable of numeric values.
|
|
84
|
+
k (Real): Target sum.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
int: Number of matching subarrays.
|
|
88
|
+
|
|
89
|
+
Raises:
|
|
90
|
+
TypeError: If arr is not iterable or contains non-numeric values.
|
|
91
|
+
TypeError: If k is not numeric.
|
|
92
|
+
|
|
93
|
+
Time Complexity: O(n)
|
|
94
|
+
Space Complexity: O(n)
|
|
95
|
+
|
|
96
|
+
Example:
|
|
97
|
+
>>> subarray_sum_equals_k([1, 1, 1], 2)
|
|
98
|
+
2
|
|
99
|
+
"""
|
|
100
|
+
values = _validate_iterable(arr)
|
|
101
|
+
if not isinstance(k, Real) or isinstance(k, bool):
|
|
102
|
+
raise TypeError("k must be numeric")
|
|
103
|
+
|
|
104
|
+
for value in values:
|
|
105
|
+
if not isinstance(value, Real) or isinstance(value, bool):
|
|
106
|
+
raise TypeError("All elements in arr must be numeric")
|
|
107
|
+
|
|
108
|
+
count = 0
|
|
109
|
+
running: Real = 0
|
|
110
|
+
seen = {0: 1}
|
|
111
|
+
for value in values:
|
|
112
|
+
running += value
|
|
113
|
+
count += seen.get(running - k, 0)
|
|
114
|
+
seen[running] = seen.get(running, 0) + 1
|
|
115
|
+
return count
|