Skip to content

Commit dbf0130

Browse files
Merge branch 'master' into add-pigeonhole-sort
2 parents 90fafee + 981ae7f commit dbf0130

14 files changed

+242
-53
lines changed

README.md

+7-3
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ If you want to uninstall algorithms, it is as simple as:
7272
- [move_zeros](algorithms/arrays/move_zeros.py)
7373
- [n_sum](algorithms/arrays/n_sum.py)
7474
- [automata](algorithms/automata)
75-
- [DFA](algorithms/automata/DFA.py)
75+
- [DFA](algorithms/automata/dfa.py)
7676
- [backtrack](algorithms/backtrack)
7777
- [general_solution.md](algorithms/backtrack/)
7878
- [add_operators](algorithms/backtrack/add_operators.py)
@@ -196,15 +196,16 @@ If you want to uninstall algorithms, it is as simple as:
196196
- [valid_sudoku](algorithms/map/valid_sudoku.py)
197197
- [word_pattern](algorithms/map/word_pattern.py)
198198
- [is_isomorphic](algorithms/map/is_isomorphic.py)
199-
- [is_anagram](algorithms/map/is_anagram.py)
199+
- [is_anagram](algorithms/map/is_anagram.py)
200200
- [maths](algorithms/maths)
201+
- [power](algorithms/maths/power.py)
201202
- [base_conversion](algorithms/maths/base_conversion.py)
202203
- [combination](algorithms/maths/combination.py)
203204
- [cosine_similarity](algorithms/maths/cosine_similarity.py)
204205
- [decimal_to_binary_ip](algorithms/maths/decimal_to_binary_ip.py)
205206
- [euler_totient](algorithms/maths/euler_totient.py)
206207
- [extended_gcd](algorithms/maths/extended_gcd.py)
207-
- [factorial](algorithms/maths/factorial.py)
208+
- [factorial](algorithms/maths/factorial.py)
208209
- [gcd/lcm](algorithms/maths/gcd.py)
209210
- [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py)
210211
- [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py)
@@ -258,6 +259,7 @@ If you want to uninstall algorithms, it is as simple as:
258259
- [search_rotate](algorithms/search/search_rotate.py)
259260
- [jump_search](algorithms/search/jump_search.py)
260261
- [next_greatest_letter](algorithms/search/next_greatest_letter.py)
262+
- [interpolation_search](algorithms/search/interpolation_search.py)
261263
- [set](algorithms/set)
262264
- [randomized_set](algorithms/set/randomized_set.py)
263265
- [set_covering](algorithms/set/set_covering.py)
@@ -283,6 +285,7 @@ If you want to uninstall algorithms, it is as simple as:
283285
- [selection_sort](algorithms/sort/selection_sort.py)
284286
- [shell_sort](algorithms/sort/shell_sort.py)
285287
- [sort_colors](algorithms/sort/sort_colors.py)
288+
- [stooge_sort](algorithms/sort/stooge_sort.py)
286289
- [top_sort](algorithms/sort/top_sort.py)
287290
- [wiggle_sort](algorithms/sort/wiggle_sort.py)
288291
- [stack](algorithms/stack)
@@ -323,6 +326,7 @@ If you want to uninstall algorithms, it is as simple as:
323326
- [judge_circle](algorithms/strings/judge_circle.py)
324327
- [strong_password](algorithms/strings/strong_password.py)
325328
- [caesar_cipher](algorithms/strings/caesar_cipher.py)
329+
- [check_pangram](algorithms/strings/check_pangram.py
326330
- [contain_string](algorithms/strings/contain_string.py)
327331
- [count_binary_substring](algorithms/strings/count_binary_substring.py)
328332
- [repeat_string](algorithms/strings/repeat_string.py)

algorithms/maths/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@
1818
from .find_order_simple import *
1919
from .find_primitive_root_simple import *
2020
from .diffie_hellman_key_exchange import *
21+
from .power import *

algorithms/maths/power.py

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
def power(a: int, n: int, r: int = None):
2+
"""
3+
Iterative version of binary exponentiation
4+
5+
Calculate a ^ n
6+
if r is specified, return the result modulo r
7+
8+
Time Complexity : O(log(n))
9+
Space Complexity : O(1)
10+
"""
11+
ans = 1
12+
while n:
13+
if n & 1:
14+
ans = ans * a
15+
a = a * a
16+
if r:
17+
ans %= r
18+
a %= r
19+
n >>= 1
20+
return ans
21+
22+
23+
def power_recur(a: int, n: int, r: int = None):
24+
"""
25+
Recursive version of binary exponentiation
26+
27+
Calculate a ^ n
28+
if r is specified, return the result modulo r
29+
30+
Time Complexity : O(log(n))
31+
Space Complexity : O(log(n))
32+
"""
33+
if n == 0:
34+
ans = 1
35+
elif n == 1:
36+
ans = a
37+
else:
38+
ans = power_recur(a, n // 2, r)
39+
ans = ans * ans
40+
if n % 2:
41+
ans = ans * a
42+
if r:
43+
ans %= r
44+
return ans
45+

algorithms/search/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@
99
from .search_rotate import *
1010
from .jump_search import *
1111
from .next_greatest_letter import *
12+
from .interpolation_search import *
+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"""
2+
Python implementation of the Interpolation Search algorithm.
3+
Given a sorted array in increasing order, interpolation search calculates
4+
the starting point of its search according to the search key.
5+
6+
FORMULA: start_pos = low + [ (x - arr[low])*(high - low) / (arr[high] - arr[low]) ]
7+
8+
Doc: https://en.wikipedia.org/wiki/Interpolation_search
9+
10+
Time Complexity: O(log2(log2 n)) for average cases, O(n) for the worst case.
11+
The algorithm performs best with uniformly distributed arrays.
12+
"""
13+
14+
from typing import List
15+
16+
17+
def interpolation_search(array: List[int], search_key: int) -> int:
18+
"""
19+
:param array: The array to be searched.
20+
:param search_key: The key to be searched in the array.
21+
22+
:returns: Index of search_key in array if found, else -1.
23+
24+
Example
25+
26+
>>> interpolation_search([1, 10, 12, 15, 20, 41, 55], 20)
27+
4
28+
>>> interpolation_search([5, 10, 12, 14, 17, 20, 21], 55)
29+
-1
30+
31+
"""
32+
33+
# highest and lowest index in array
34+
high = len(array) - 1
35+
low = 0
36+
37+
while low <= high and search_key in range(low, array[high] + 1):
38+
# calculate the search position
39+
pos = low + int(((search_key - array[low]) *
40+
(high - low) / (array[high] - array[low])))
41+
42+
# if array[pos] equals the search_key then return pos as the index
43+
if search_key == array[pos]:
44+
return pos
45+
# if the search_key is greater than array[pos] restart the search with the
46+
# subarray greater than array[pos]
47+
elif search_key > array[pos]:
48+
low = pos + 1
49+
# in this case start the search with the subarray smaller than current array[pos]
50+
elif search_key < array[pos]:
51+
high = pos - 1
52+
53+
return -1

algorithms/sort/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from .top_sort import *
1515
from .bucket_sort import *
1616
from .shell_sort import *
17+
from .stooge_sort import *
1718
from .radix_sort import *
1819
from .gnome_sort import *
1920
from .cocktail_shaker_sort import *

algorithms/sort/stooge_sort.py

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
'''
2+
3+
Stooge Sort
4+
Time Complexity : O(n2.709)
5+
Reference: https://www.geeksforgeeks.org/stooge-sort/
6+
7+
'''
8+
9+
10+
11+
def stoogesort(arr, l, h):
12+
if l >= h:
13+
return
14+
15+
# If first element is smaller
16+
# than last, swap them
17+
if arr[l]>arr[h]:
18+
t = arr[l]
19+
arr[l] = arr[h]
20+
arr[h] = t
21+
22+
# If there are more than 2 elements in
23+
# the array
24+
if h-l + 1 > 2:
25+
t = (int)((h-l + 1)/3)
26+
27+
# Recursively sort first 2 / 3 elements
28+
stoogesort(arr, l, (h-t))
29+
30+
# Recursively sort last 2 / 3 elements
31+
stoogesort(arr, l + t, (h))
32+
33+
# Recursively sort first 2 / 3 elements
34+
# again to confirm
35+
stoogesort(arr, l, (h-t))
36+
37+
38+
if __name__ == "__main__":
39+
array = [1,3,64,5,7,8]
40+
n = len(array)
41+
stoogesort(array, 0, n-1)
42+
for i in range(0, n):
43+
print(array[i], end = ' ')

algorithms/strings/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from .judge_circle import *
2626
from .strong_password import *
2727
from .caesar_cipher import *
28+
from .check_pangram import *
2829
from .contain_string import *
2930
from .count_binary_substring import *
3031
from .repeat_string import *

algorithms/strings/check_pangram.py

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
"""
2+
Algorithm that checks if a given string is a pangram or not
3+
"""
4+
5+
def check_pangram(input_string):
6+
alphabet = "abcdefghijklmnopqrstuvwxyz"
7+
for ch in alphabet:
8+
if ch not in input_string.lower():
9+
return False
10+
return True

algorithms/strings/is_palindrome.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ def is_palindrome(s):
2121
i = 0
2222
j = len(s)-1
2323
while i < j:
24-
while i < j and not s[i].isalnum():
24+
while not s[i].isalnum():
2525
i += 1
26-
while i < j and not s[j].isalnum():
26+
while not s[j].isalnum():
2727
j -= 1
2828
if s[i].lower() != s[j].lower():
2929
return False

tests/test_maths.py

+22
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from algorithms.maths import (
2+
power,power_recur,
23
int_to_base, base_to_int,
34
decimal_to_binary_ip,
45
euler_totient,
@@ -25,6 +26,27 @@
2526
import unittest
2627

2728

29+
class TestPower(unittest.TestCase):
30+
"""
31+
Test for the file power.py
32+
33+
Arguments:
34+
unittest {[type]} -- [description]
35+
"""
36+
37+
def test_power(self):
38+
self.assertEqual(8, power(2, 3))
39+
self.assertEqual(1, power(5, 0))
40+
self.assertEqual(0, power(10, 3, 5))
41+
self.assertEqual(280380, power(2265, 1664,465465))
42+
43+
def test_power_recur(self):
44+
self.assertEqual(8, power_recur(2, 3))
45+
self.assertEqual(1, power_recur(5, 0))
46+
self.assertEqual(0, power_recur(10, 3, 5))
47+
self.assertEqual(280380, power_recur(2265, 1664,465465))
48+
49+
2850
class TestBaseConversion(unittest.TestCase):
2951
"""
3052
Test for the file base_conversion.py

tests/test_search.py

+14-2
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@
99
find_min_rotate, find_min_rotate_recur,
1010
search_rotate, search_rotate_recur,
1111
jump_search,
12-
next_greatest_letter, next_greatest_letter_v1, next_greatest_letter_v2
12+
next_greatest_letter, next_greatest_letter_v1, next_greatest_letter_v2,
13+
interpolation_search
1314
)
1415

1516
import unittest
1617

18+
1719
class TestSuite(unittest.TestCase):
1820

1921
def test_first_occurrence(self):
@@ -56,7 +58,7 @@ def test_linear_search(self):
5658
self.assertEqual(-1, linear_search(array, -1))
5759

5860
def test_search_insert(self):
59-
array = [1,3,5,6]
61+
array = [1, 3, 5, 6]
6062
self.assertEqual(2, search_insert(array, 5))
6163
self.assertEqual(1, search_insert(array, 2))
6264
self.assertEqual(4, search_insert(array, 7))
@@ -122,6 +124,16 @@ def test_next_greatest_letter(self):
122124
self.assertEqual("c", next_greatest_letter_v1(letters, target))
123125
self.assertEqual("c", next_greatest_letter_v2(letters, target))
124126

127+
def test_interpolation_search(self):
128+
array = [0, 3, 5, 5, 9, 12, 12, 15, 16, 19, 20]
129+
self.assertEqual(1, interpolation_search(array, 3))
130+
self.assertEqual(2, interpolation_search(array, 5))
131+
self.assertEqual(6, interpolation_search(array, 12))
132+
self.assertEqual(-1, interpolation_search(array, 22))
133+
self.assertEqual(-1, interpolation_search(array, -10))
134+
self.assertEqual(10, interpolation_search(array, 20))
135+
136+
125137
if __name__ == '__main__':
126138

127139
unittest.main()

0 commit comments

Comments
 (0)