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.
Files changed (78) hide show
  1. algonest-0.1.0/LICENSE +21 -0
  2. algonest-0.1.0/PKG-INFO +77 -0
  3. algonest-0.1.0/README.md +48 -0
  4. algonest-0.1.0/algonest/__init__.py +223 -0
  5. algonest-0.1.0/algonest/arrays/__init__.py +21 -0
  6. algonest-0.1.0/algonest/arrays/dutch_flag.py +92 -0
  7. algonest-0.1.0/algonest/arrays/kadane.py +42 -0
  8. algonest-0.1.0/algonest/arrays/prefix_sum.py +115 -0
  9. algonest-0.1.0/algonest/arrays/sliding_window.py +90 -0
  10. algonest-0.1.0/algonest/arrays/two_pointers.py +119 -0
  11. algonest-0.1.0/algonest/dynamic_programming/__init__.py +19 -0
  12. algonest-0.1.0/algonest/dynamic_programming/coin_change.py +26 -0
  13. algonest-0.1.0/algonest/dynamic_programming/edit_distance.py +26 -0
  14. algonest-0.1.0/algonest/dynamic_programming/knapsack.py +23 -0
  15. algonest-0.1.0/algonest/dynamic_programming/lcs.py +17 -0
  16. algonest-0.1.0/algonest/dynamic_programming/lis.py +26 -0
  17. algonest-0.1.0/algonest/dynamic_programming/matrix_chain.py +27 -0
  18. algonest-0.1.0/algonest/graphs/__init__.py +27 -0
  19. algonest-0.1.0/algonest/graphs/bellman_ford.py +30 -0
  20. algonest-0.1.0/algonest/graphs/bfs.py +53 -0
  21. algonest-0.1.0/algonest/graphs/dfs.py +65 -0
  22. algonest-0.1.0/algonest/graphs/dijkstra.py +29 -0
  23. algonest-0.1.0/algonest/graphs/dsu.py +32 -0
  24. algonest-0.1.0/algonest/graphs/floyd_warshall.py +17 -0
  25. algonest-0.1.0/algonest/graphs/kruskal.py +21 -0
  26. algonest-0.1.0/algonest/graphs/prim.py +28 -0
  27. algonest-0.1.0/algonest/graphs/topological_sort.py +52 -0
  28. algonest-0.1.0/algonest/heap/__init__.py +7 -0
  29. algonest-0.1.0/algonest/heap/max_heap.py +95 -0
  30. algonest-0.1.0/algonest/heap/min_heap.py +95 -0
  31. algonest-0.1.0/algonest/heap/priority_queue.py +128 -0
  32. algonest-0.1.0/algonest/linked_list/__init__.py +14 -0
  33. algonest-0.1.0/algonest/linked_list/circular.py +120 -0
  34. algonest-0.1.0/algonest/linked_list/doubly.py +98 -0
  35. algonest-0.1.0/algonest/linked_list/node.py +32 -0
  36. algonest-0.1.0/algonest/linked_list/singly.py +121 -0
  37. algonest-0.1.0/algonest/math/__init__.py +31 -0
  38. algonest-0.1.0/algonest/math/bit_manipulation.py +33 -0
  39. algonest-0.1.0/algonest/math/fast_power.py +16 -0
  40. algonest-0.1.0/algonest/math/gcd_lcm.py +32 -0
  41. algonest-0.1.0/algonest/math/modular_arithmetic.py +46 -0
  42. algonest-0.1.0/algonest/math/prime_sieve.py +47 -0
  43. algonest-0.1.0/algonest/search/__init__.py +19 -0
  44. algonest-0.1.0/algonest/search/binary_search.py +223 -0
  45. algonest-0.1.0/algonest/sort/__init__.py +23 -0
  46. algonest-0.1.0/algonest/sort/sorting.py +320 -0
  47. algonest-0.1.0/algonest/stack_queue/__init__.py +14 -0
  48. algonest-0.1.0/algonest/stack_queue/deque.py +83 -0
  49. algonest-0.1.0/algonest/stack_queue/monotonic_stack.py +84 -0
  50. algonest-0.1.0/algonest/stack_queue/queue.py +69 -0
  51. algonest-0.1.0/algonest/stack_queue/stack.py +68 -0
  52. algonest-0.1.0/algonest/strings/__init__.py +18 -0
  53. algonest-0.1.0/algonest/strings/anagram.py +54 -0
  54. algonest-0.1.0/algonest/strings/kmp.py +39 -0
  55. algonest-0.1.0/algonest/strings/rabin_karp.py +31 -0
  56. algonest-0.1.0/algonest/strings/trie.py +59 -0
  57. algonest-0.1.0/algonest/strings/z_algorithm.py +34 -0
  58. algonest-0.1.0/algonest/trees/__init__.py +22 -0
  59. algonest-0.1.0/algonest/trees/avl_tree.py +87 -0
  60. algonest-0.1.0/algonest/trees/binary_tree.py +109 -0
  61. algonest-0.1.0/algonest/trees/bst.py +150 -0
  62. algonest-0.1.0/algonest/trees/fenwick_tree.py +43 -0
  63. algonest-0.1.0/algonest/trees/node.py +19 -0
  64. algonest-0.1.0/algonest/trees/segment_tree.py +101 -0
  65. algonest-0.1.0/algonest/trees/traversals.py +104 -0
  66. algonest-0.1.0/algonest/utils/__init__.py +20 -0
  67. algonest-0.1.0/algonest/utils/debug.py +63 -0
  68. algonest-0.1.0/algonest/utils/fast_io.py +67 -0
  69. algonest-0.1.0/algonest/utils/test_runner.py +59 -0
  70. algonest-0.1.0/algonest/utils/type_helpers.py +6 -0
  71. algonest-0.1.0/algonest/utils/validators.py +36 -0
  72. algonest-0.1.0/algonest.egg-info/PKG-INFO +77 -0
  73. algonest-0.1.0/algonest.egg-info/SOURCES.txt +76 -0
  74. algonest-0.1.0/algonest.egg-info/dependency_links.txt +1 -0
  75. algonest-0.1.0/algonest.egg-info/requires.txt +4 -0
  76. algonest-0.1.0/algonest.egg-info/top_level.txt +1 -0
  77. algonest-0.1.0/pyproject.toml +41 -0
  78. 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.
@@ -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
+ ```
@@ -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