Skip to content

Commit f40b7a6

Browse files
authored
Merge pull request #15 from rlishtaba/feature/algorithms
Adding new algorithms
2 parents a83f1fd + d59c636 commit f40b7a6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+952
-52
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.*

README.md

+69-33
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ $ pip install py-algorithms
3333
- Min PQ
3434
- Max PQ
3535
- Suffix Array
36-
36+
3737
---
3838

3939
### Search
4040
- Binary Search
41-
41+
4242
---
4343

4444
### Sort
@@ -49,43 +49,51 @@ $ pip install py-algorithms
4949
- Comb Sort
5050
- Bubble Sort
5151
- Selection Sort
52-
52+
5353
---
5454

5555
### Graph Algorithms
5656
- Depth-First-Search (DFS)
57-
- Breadth-First-Search (BFS)
57+
- Breadth-First-Search (BFS)
5858
- Topologial sort
5959
- Floyd–Warshall algorithm
60-
60+
6161
---
6262

63-
### String Algorithms
63+
### String Algorithms
6464
- Patttern Matching
65-
- Boyer–Moore string search
66-
- Knut-Morris-Prat string search
67-
68-
---
65+
- Boyer–Moore string search
66+
- Knut-Morris-Prat string search
67+
68+
---
6969

7070
### Primality Tests
7171
- Miller-Rabin primality test
7272
- Simple primality test
73-
73+
7474
---
75-
75+
7676
### Algorithms
7777
- Quick Union
7878
- Union Find
7979
- Weighted Union Find
8080
- Weighted Union Find with Path Compression
81-
81+
82+
---
83+
84+
### Dynamic Programing (DP)
85+
86+
- Longest Increasing Subsequence (LIS)
87+
- Levenshtein Distance
88+
- 0-1 Knapsack Problem
89+
8290
---
8391

8492
### Challenges
8593
- TopCoder (www.topcoder.com)
8694
- HackerRank problems & submissions (https://www.hackerrank.com)
8795
- CoderByte challenges (https://coderbyte.com)
88-
96+
8997
---
9098

9199
### Challenges
@@ -492,11 +500,11 @@ ds.is_sub_str('blah') #=> False
492500

493501
#### Topological sort
494502

495-
In the field of computer science, a topological sort or topological ordering of a directed graph is a
503+
In the field of computer science, a topological sort or topological ordering of a directed graph is a
496504
linear ordering of its vertices such that for every directed edge uv from vertex u to vertex v, u comes before v in the ordering.
497-
For instance, the vertices of the graph may represent tasks to be performed, and the edges may represent
498-
constraints that one task must be performed before another; in this application, a topological ordering is just a valid sequence for the tasks.
499-
A topological ordering is possible if and only if the graph has no directed cycles, that is, if it is a directed acyclic graph (DAG).
505+
For instance, the vertices of the graph may represent tasks to be performed, and the edges may represent
506+
constraints that one task must be performed before another; in this application, a topological ordering is just a valid sequence for the tasks.
507+
A topological ordering is possible if and only if the graph has no directed cycles, that is, if it is a directed acyclic graph (DAG).
500508
Any DAG has at least one topological ordering, and algorithms are known for constructing a topological ordering of any DAG in linear time.
501509

502510
![topo-sort](http://www.stoimen.com/blog/wp-content/uploads/2012/10/2.-Topological-Sort.png)
@@ -521,7 +529,7 @@ dag.insert_edge(d, e, None)
521529
topological_sort_f1(dag) #=> [#<Vertex(C)>, #<Vertex(B)>, #<Vertex(D)>, #<Vertex(A)>, #<Vertex(E)>]
522530

523531
```
524-
532+
525533
---
526534

527535
### String Algorithms
@@ -530,11 +538,11 @@ topological_sort_f1(dag) #=> [#<Vertex(C)>, #<Vertex(B)>, #<Vertex(D)>, #<Vertex
530538

531539
#### Boyer–Moore string search algorithm
532540

533-
In computer science, the Boyer–Moore string search algorithm is an efficient string searching algorithm that
541+
In computer science, the Boyer–Moore string search algorithm is an efficient string searching algorithm that
534542
is the standard benchmark for practical string search literature. It was developed by Robert S. Boyer and J Strother Moore in 1977.
535-
The algorithm preprocesses the string being searched for (the pattern), but not the string being searched in (the text).
536-
It is thus well-suited for applications in which the pattern is much shorter than the text or where it persists across multiple searches.
537-
The Boyer-Moore algorithm uses information gathered during the preprocess step to skip sections of the text,
543+
The algorithm preprocesses the string being searched for (the pattern), but not the string being searched in (the text).
544+
It is thus well-suited for applications in which the pattern is much shorter than the text or where it persists across multiple searches.
545+
The Boyer-Moore algorithm uses information gathered during the preprocess step to skip sections of the text,
538546
resulting in a lower constant factor than many other string search algorithms.
539547

540548
```python
@@ -555,18 +563,18 @@ algorithm('foo' + substr + 'bar', substr) # => 3
555563
![primes](https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Gaussian_integer_lattice.svg/389px-Gaussian_integer_lattice.svg.png)
556564

557565
A primality test is an algorithm for determining whether an input number is prime.
558-
Among other fields of mathematics, it is used for cryptography.
559-
Unlike integer factorization, primality tests do not generally give prime factors, only stating whether the input number
560-
is prime or not. Factorization is thought to be a computationally difficult problem, whereas primality
561-
testing is comparatively easy (its running time is polynomial in the size of the input).
562-
Some primality tests prove that a number is prime, while others like Miller–Rabin prove that a number is composite.
566+
Among other fields of mathematics, it is used for cryptography.
567+
Unlike integer factorization, primality tests do not generally give prime factors, only stating whether the input number
568+
is prime or not. Factorization is thought to be a computationally difficult problem, whereas primality
569+
testing is comparatively easy (its running time is polynomial in the size of the input).
570+
Some primality tests prove that a number is prime, while others like Miller–Rabin prove that a number is composite.
563571
Therefore, the latter might be called compositeness tests instead of primality tests.
564572

565573

566574
#### Miller-Rabin Primality Test
567-
568-
The Miller–Rabin primality test or Rabin–Miller primality test is a primality test: an algorithm which determines whether a given number is prime,
569-
similar to the Fermat primality test and the Solovay–Strassen primality test. Its original version, due to Gary L. Miller, is deterministic,
575+
576+
The Miller–Rabin primality test or Rabin–Miller primality test is a primality test: an algorithm which determines whether a given number is prime,
577+
similar to the Fermat primality test and the Solovay–Strassen primality test. Its original version, due to Gary L. Miller, is deterministic,
570578
but the correctness relies on the unproven Extended Riemann hypothesis; Michael O. Rabin modified it to obtain an unconditional probabilistic algorithm.
571579

572580
```python
@@ -575,7 +583,7 @@ from py_algorithms.primality_tests import new_miller_rabin_primality_test
575583
algorithm = new_miller_rabin_primality_test()
576584

577585
algorithm(199) #=> True, 199 is a prime number
578-
algorithm(4) #=> False, 4 % 2 == 0, therefore, 4 is not a prime number.
586+
algorithm(4) #=> False, 4 % 2 == 0, therefore, 4 is not a prime number.
579587

580588
```
581589

@@ -590,12 +598,40 @@ from py_algorithms.primality_tests import new_simple_primality_test
590598
algorithm = new_simple_primality_test()
591599

592600
algorithm(32416190071) #=> True, 32416190071 is a prime number
593-
algorithm(4) #=> False, 4 % 2 == 0, therefore, 4 is not a prime number.
601+
algorithm(4) #=> False, 4 % 2 == 0, therefore, 4 is not a prime number.
594602

595603
```
596604

597605
---
598606

607+
### Dynamic Programing (DP)
608+
In computer science, mathematics, management science, economics and bioinformatics,
609+
dynamic programming (also known as dynamic optimization) is a method for solving a complex problem
610+
by breaking it down into a collection of simpler subproblems, solving each of those subproblems
611+
just once, and storing their solutions. The next time the same subproblem occurs,
612+
instead of recomputing its solution, one simply looks up the previously computed solution,
613+
thereby saving computation time at the expense of a (hopefully) modest expenditure in storage space.
614+
(Each of the subproblem solutions is indexed in some way, typically based on the values of its input parameters,
615+
so as to facilitate its lookup.) The technique of storing solutions to subproblems instead of recomputing them is called "memoization".
616+
617+
618+
###
619+
In information theory, Linguistics and computer science, the Levenshtein distance is a string metric for measuring the difference between two sequences.
620+
Informally, the Levenshtein distance between two words is the minimum number of single-character edits (insertions, deletions or substitutions) required to change one word into the other.
621+
It is named after Vladimir Levenshtein, who considered this distance in 1965.
622+
Levenshtein distance may also be referred to as edit distance, although that term may also denote a larger family of distance metrics.
623+
624+
It is closely related to pairwise string alignments.
625+
626+
```python
627+
from py_algorithms.strings import new_levenshtein_distance
628+
629+
distance = new_levenshtein_distance(list('Moon'), list("Moore"))
630+
assert 2 == distance
631+
```
632+
633+
---------
634+
599635

600636
## Contributing
601637

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)

0 commit comments

Comments
 (0)