Skip to content

Commit 9f00bb8

Browse files
committed
Adding new algorithms
1 parent a83f1fd commit 9f00bb8

34 files changed

+729
-17
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,4 @@ ENV/
109109

110110
/junit-report.xml
111111
/release.sh
112-
/debugger.py
112+
/debugger.*

py_algorithms/array/__init__.py

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
__all__ = [
2+
'new_circular_array'
3+
]
4+
5+
from .circular_array import CircularArray
6+
7+
8+
def new_circular_array(size: int = 5) -> CircularArray:
9+
"""
10+
Factory method
11+
:param size: initial array size
12+
:return: CircularArray
13+
"""
14+
return CircularArray(size)

py_algorithms/array/circular_array.py

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
class CircularArray:
2+
__slots__ = '_list', '_front', '_rear', '_n'
3+
4+
def __init__(self, n):
5+
self._list = [None for _ in range(n)]
6+
self._n = n
7+
self._front = 0
8+
self._rear = 0
9+
10+
def size(self):
11+
if self._rear >= self._front:
12+
return self._rear - self._front
13+
return self._n - (self._front - self._rear)
14+
15+
def enqueue(self, item):
16+
size = self.size()
17+
if size == self._n - 1:
18+
self._resize(lambda x: x * 2)
19+
self._list[self._rear] = item
20+
self._rear = (self._rear + 1) % self._n
21+
22+
def dequeue(self):
23+
size = self.size()
24+
if size == 0:
25+
raise RuntimeError("Empty")
26+
data = self._list[self._front]
27+
self._list[self._front] = float("inf")
28+
self._front = (self._front + 1) % self._n
29+
return data
30+
31+
def _resize(self, strategy_f):
32+
new_size = strategy_f(self._n)
33+
xs = [None for _ in range(new_size)]
34+
i = self._front
35+
j = 0
36+
while i != self._rear:
37+
xs[j] = self._list[i]
38+
i = (i + 1) % self._n
39+
j += 1
40+
41+
self._front = 0
42+
self._rear = j
43+
self._n = new_size
44+
self._list = xs
45+
46+
47+
if __name__ == '__main__':
48+
arr = CircularArray(5)
49+
arr.enqueue(1)
50+
arr.enqueue(2)
51+
arr.enqueue(3)
52+
print(arr.dequeue())
53+
print(arr.dequeue())
54+
arr.enqueue(9)
55+
arr.enqueue(4)
56+
arr.enqueue(5)
57+
arr.enqueue(6)
58+
arr.enqueue(7)
59+
arr.enqueue(8)
60+
arr

py_algorithms/data_structures/__init__.py

+23-16
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,21 @@
1+
__all__ = [
2+
'new_deque',
3+
'Deque',
4+
'new_queue',
5+
'Queue',
6+
'new_stack',
7+
'Stack',
8+
'new_heap',
9+
'Heap',
10+
'new_max_heap',
11+
'new_min_heap',
12+
'new_priority_queue',
13+
'PriorityQueue',
14+
'new_suffix_array',
15+
'new_tree_node',
16+
'TreeNode',
17+
]
18+
119
from typing import Any
220
from typing import Callable
321
from typing import List
@@ -12,25 +30,10 @@
1230
from .queue import Queue
1331
from .stack import Stack
1432
from .suffix_array import SuffixArray
33+
from .tree_node import TreeNode
1534

1635
T = TypeVar('T')
1736

18-
__all__ = [
19-
'new_deque',
20-
'Deque',
21-
'new_queue',
22-
'Queue',
23-
'new_stack',
24-
'Stack',
25-
'new_heap',
26-
'Heap',
27-
'new_max_heap',
28-
'new_min_heap',
29-
'new_priority_queue',
30-
'PriorityQueue',
31-
'new_suffix_array',
32-
]
33-
3437

3538
def new_deque(collection: List[Any] = ()) -> Deque:
3639
"""
@@ -134,3 +137,7 @@ def new_suffix_array(string: str) -> SuffixArray:
134137
:return: SuffixArray interface
135138
"""
136139
return SuffixArray(string)
140+
141+
142+
def new_tree_node(element, left=None, right=None):
143+
return TreeNode(element=element, left=left, right=right)

py_algorithms/data_structures/stack.py

+6
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,9 @@ def size(self) -> int:
2828

2929
def is_empty(self) -> bool:
3030
return self._deque.is_empty()
31+
32+
def peek(self):
33+
if self.size > 0:
34+
return self._deque.back
35+
raise IndexError('Cannot perform top, stack size: {}'
36+
.format(self.size))
+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from typing import Any
2+
3+
4+
class TreeNode:
5+
__slots__ = '_left', '_right', '_element'
6+
7+
def __init__(self, left, right, element=None):
8+
self._right = right
9+
self._left = left
10+
self._element = element
11+
12+
@property
13+
def left(self) -> 'TreeNode':
14+
return self._left
15+
16+
def set_left(self, node: 'TreeNode') -> 'TreeNode':
17+
self._left = node
18+
return self
19+
20+
@property
21+
def right(self) -> 'TreeNode':
22+
return self._right
23+
24+
def set_right(self, node: 'TreeNode') -> 'TreeNode':
25+
self._right = node
26+
return self
27+
28+
@property
29+
def element(self) -> Any:
30+
return self._element
31+
32+
def __repr__(self):
33+
return "#<{} e={} left={} right={}>" \
34+
.format(self.__class__.__name__, self.element, self.left, self.right)

py_algorithms/lists/__init__.py

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
__all__ = [
2+
'Node',
3+
'new_singly_linked_node',
4+
'merge_linked_lists',
5+
]
6+
7+
from .node import Node
8+
from .merge_two_sorted import MergeTwoSorted
9+
10+
11+
def new_singly_linked_node(data, successor=None):
12+
return Node(data, successor)
13+
14+
15+
def merge_linked_lists(a: Node, b: Node) -> Node:
16+
return MergeTwoSorted.apply(a, b)
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from .node import Node
2+
3+
4+
class FindMergePoint:
5+
@staticmethod
6+
def apply(a: Node, b: Node) -> Node:
7+
head_a = a
8+
head_b = b
9+
i = 0
10+
while head_a != head_b:
11+
if head_a.next is None:
12+
head_a = b
13+
else:
14+
head_a = head_a.next
15+
16+
if head_b.next is None:
17+
head_b = a
18+
else:
19+
head_b = head_b.next
20+
i += 1
21+
print(i)
22+
23+
return head_b
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from .node import Node
2+
3+
4+
class MergeTwoSorted:
5+
@staticmethod
6+
def apply(a: Node, b: Node) -> Node:
7+
ptr = Node(-1, None)
8+
head = ptr
9+
while a is not None and b is not None:
10+
11+
if a.data < b.data:
12+
head.next = a
13+
a = a.next
14+
else:
15+
head.next = b
16+
b = b.next
17+
18+
head = head.next
19+
20+
if a:
21+
head.next = a
22+
23+
if b:
24+
head.next = b
25+
26+
return ptr.next

py_algorithms/lists/node.py

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
class Node:
2+
__slots__ = '_data', '_next'
3+
4+
def __init__(self, data, successor):
5+
self._next = successor
6+
self._data = data
7+
8+
@property
9+
def data(self):
10+
return self._data
11+
12+
@property
13+
def next(self):
14+
return self._next
15+
16+
@next.setter
17+
def next(self, other: 'Node'):
18+
if other is None:
19+
self._next = None
20+
return
21+
22+
if not isinstance(other, self.__class__):
23+
raise ValueError("Type invariant violation.")
24+
self._next = other
25+
26+
def __repr__(self):
27+
return '#<{} data={} next={}>' \
28+
.format(self.__class__.__name__, self.data, self.next)

py_algorithms/stacks/__init__.py

Whitespace-only changes.

py_algorithms/stacks/finding_spans.py

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from typing import List
2+
3+
from ..data_structures import new_stack
4+
5+
6+
class FindingSpans:
7+
"""
8+
9+
"""
10+
11+
@staticmethod
12+
def apply(xs: List[int]):
13+
stack = new_stack()
14+
state = [float('inf') for _ in range(len(xs))]
15+
16+
for i in range(0, len(xs)):
17+
while not stack.is_empty() and xs[i] > xs[stack.peek()]:
18+
stack.pop()
19+
20+
if stack.is_empty():
21+
p = -1
22+
else:
23+
p = stack.peek()
24+
25+
state[i] = i - p
26+
stack.push(i)
27+
return state
28+
29+
30+
if __name__ == '__main__':
31+
data = [6, 3, 4, 5, 2]
32+
assert FindingSpans.apply(data) == []
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from typing import Any
2+
from typing import List
3+
4+
5+
class ReplaceWithNearestGreatest:
6+
@staticmethod
7+
def apply(xs: List[Any]) -> List[Any]:
8+
result = []
9+
stack = [xs[0]]
10+
for i in range(0, len(xs)):
11+
nearest_gt = xs[i]
12+
if len(stack) > 0:
13+
element = stack.pop()
14+
while element < nearest_gt:
15+
result.append(nearest_gt)
16+
if len(stack) == 0:
17+
break
18+
element = stack.pop()
19+
if element > nearest_gt:
20+
stack.append(element)
21+
stack.append(nearest_gt)
22+
23+
while len(stack) > 0:
24+
stack.pop()
25+
result.append(float('inf'))
26+
27+
return result
28+
29+
30+
if __name__ == '__main__':
31+
f = ReplaceWithNearestGreatest()
32+
_xs = [0, 0, 1, 0, 3, 0, 4]
33+
assert f.apply(_xs) == [1, 3, 3, 4, 4, float('inf')]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from typing import List
2+
3+
4+
class GenBinStringsWithNBits1:
5+
def __call__(self, n: int) -> List[str]:
6+
if n == 0:
7+
return []
8+
if n == 1:
9+
return ['0', '1']
10+
11+
xs = []
12+
13+
for bitstring in self(n - 1):
14+
for digit in self(1):
15+
xs.append(digit + bitstring)
16+
17+
return xs
18+
19+
20+
class GenBinStringsWithNBits2:
21+
def __call__(self, num: int, f) -> List[str]:
22+
if num == 0:
23+
return []
24+
if num == 1:
25+
return ['0', '1']
26+
left = f('0', self(num - 1, f))
27+
right = f('1', self(num - 1, f))
28+
return left + right
29+
30+
31+
def _append_at_beginning_front(x, xs):
32+
return [x + element for element in xs]
33+
34+
35+
if __name__ == '__main__':
36+
print(GenBinStringsWithNBits1()(4))
37+
print(GenBinStringsWithNBits2()(4, _append_at_beginning_front))

0 commit comments

Comments
 (0)