Skip to content

Commit

Permalink
Merge branch 'TheAlgorithms:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
Ramy-Badr-Ahmed authored Jan 13, 2025
2 parents f1387e7 + 4fe50bc commit e27c028
Show file tree
Hide file tree
Showing 29 changed files with 138 additions and 102 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ repos:
- id: auto-walrus

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.6
rev: v0.9.1
hooks:
- id: ruff
- id: ruff-format
Expand Down
4 changes: 2 additions & 2 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
* [Baconian Cipher](ciphers/baconian_cipher.py)
* [Base16](ciphers/base16.py)
* [Base32](ciphers/base32.py)
* [Base64](ciphers/base64.py)
* [Base64 Cipher](ciphers/base64_cipher.py)
* [Base85](ciphers/base85.py)
* [Beaufort Cipher](ciphers/beaufort_cipher.py)
* [Bifid](ciphers/bifid.py)
Expand Down Expand Up @@ -1331,7 +1331,7 @@
* [Title](strings/title.py)
* [Top K Frequent Words](strings/top_k_frequent_words.py)
* [Upper](strings/upper.py)
* [Wave](strings/wave.py)
* [Wave String](strings/wave_string.py)
* [Wildcard Pattern Matching](strings/wildcard_pattern_matching.py)
* [Word Occurrence](strings/word_occurrence.py)
* [Word Patterns](strings/word_patterns.py)
Expand Down
34 changes: 34 additions & 0 deletions backtracking/all_combinations.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

def combination_lists(n: int, k: int) -> list[list[int]]:
"""
Generates all possible combinations of k numbers out of 1 ... n using itertools.
>>> combination_lists(n=4, k=2)
[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
"""
Expand All @@ -20,6 +22,8 @@ def combination_lists(n: int, k: int) -> list[list[int]]:

def generate_all_combinations(n: int, k: int) -> list[list[int]]:
"""
Generates all possible combinations of k numbers out of 1 ... n using backtracking.
>>> generate_all_combinations(n=4, k=2)
[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
>>> generate_all_combinations(n=0, k=0)
Expand All @@ -34,6 +38,14 @@ def generate_all_combinations(n: int, k: int) -> list[list[int]]:
ValueError: n must not be negative
>>> generate_all_combinations(n=5, k=4)
[[1, 2, 3, 4], [1, 2, 3, 5], [1, 2, 4, 5], [1, 3, 4, 5], [2, 3, 4, 5]]
>>> generate_all_combinations(n=3, k=3)
[[1, 2, 3]]
>>> generate_all_combinations(n=3, k=1)
[[1], [2], [3]]
>>> generate_all_combinations(n=1, k=0)
[[]]
>>> generate_all_combinations(n=1, k=1)
[[1]]
>>> from itertools import combinations
>>> all(generate_all_combinations(n, k) == combination_lists(n, k)
... for n in range(1, 6) for k in range(1, 6))
Expand All @@ -56,6 +68,28 @@ def create_all_state(
current_list: list[int],
total_list: list[list[int]],
) -> None:
"""
Helper function to recursively build all combinations.
>>> create_all_state(1, 4, 2, [], result := [])
>>> result
[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
>>> create_all_state(1, 3, 3, [], result := [])
>>> result
[[1, 2, 3]]
>>> create_all_state(2, 2, 1, [1], result := [])
>>> result
[[1, 2]]
>>> create_all_state(1, 0, 0, [], result := [])
>>> result
[[]]
>>> create_all_state(1, 4, 0, [1, 2], result := [])
>>> result
[[1, 2]]
>>> create_all_state(5, 4, 2, [1, 2], result := [])
>>> result
[]
"""
if level == 0:
total_list.append(current_list[:])
return
Expand Down
12 changes: 6 additions & 6 deletions ciphers/base64.py → ciphers/base64_cipher.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,13 @@ def base64_decode(encoded_data: str) -> bytes:

# Check if the encoded string contains non base64 characters
if padding:
assert all(
char in B64_CHARSET for char in encoded_data[:-padding]
), "Invalid base64 character(s) found."
assert all(char in B64_CHARSET for char in encoded_data[:-padding]), (
"Invalid base64 character(s) found."
)
else:
assert all(
char in B64_CHARSET for char in encoded_data
), "Invalid base64 character(s) found."
assert all(char in B64_CHARSET for char in encoded_data), (
"Invalid base64 character(s) found."
)

# Check the padding
assert len(encoded_data) % 4 == 0 and padding < 3, "Incorrect padding"
Expand Down
2 changes: 1 addition & 1 deletion ciphers/caesar_cipher.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ def brute_force(input_string: str, alphabet: str | None = None) -> dict[int, str

if __name__ == "__main__":
while True:
print(f'\n{"-" * 10}\n Menu\n{"-" * 10}')
print(f"\n{'-' * 10}\n Menu\n{'-' * 10}")
print(*["1.Encrypt", "2.Decrypt", "3.BruteForce", "4.Quit"], sep="\n")

# get user input
Expand Down
2 changes: 1 addition & 1 deletion computer_vision/flip_augmentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def main() -> None:
file_name = paths[index].split(os.sep)[-1].rsplit(".", 1)[0]
file_root = f"{OUTPUT_DIR}/{file_name}_FLIP_{letter_code}"
cv2.imwrite(f"{file_root}.jpg", image, [cv2.IMWRITE_JPEG_QUALITY, 85])
print(f"Success {index+1}/{len(new_images)} with {file_name}")
print(f"Success {index + 1}/{len(new_images)} with {file_name}")
annos_list = []
for anno in new_annos[index]:
obj = f"{anno[0]} {anno[1]} {anno[2]} {anno[3]} {anno[4]}"
Expand Down
2 changes: 1 addition & 1 deletion computer_vision/mosaic_augmentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def main() -> None:
file_name = path.split(os.sep)[-1].rsplit(".", 1)[0]
file_root = f"{OUTPUT_DIR}/{file_name}_MOSAIC_{letter_code}"
cv2.imwrite(f"{file_root}.jpg", new_image, [cv2.IMWRITE_JPEG_QUALITY, 85])
print(f"Succeeded {index+1}/{NUMBER_IMAGES} with {file_name}")
print(f"Succeeded {index + 1}/{NUMBER_IMAGES} with {file_name}")
annos_list = []
for anno in new_annos:
width = anno[3] - anno[1]
Expand Down
6 changes: 3 additions & 3 deletions data_structures/hashing/number_theory/prime_numbers.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ def is_prime(number: int) -> bool:
"""

# precondition
assert isinstance(number, int) and (
number >= 0
), "'number' must been an int and positive"
assert isinstance(number, int) and (number >= 0), (
"'number' must been an int and positive"
)

if 1 < number < 4:
# 2 and 3 are primes
Expand Down
6 changes: 3 additions & 3 deletions data_structures/heap/min_heap.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,9 @@ def is_empty(self):
return len(self.heap) == 0

def decrease_key(self, node, new_value):
assert (
self.heap[self.idx_of_element[node]].val > new_value
), "newValue must be less that current value"
assert self.heap[self.idx_of_element[node]].val > new_value, (
"newValue must be less that current value"
)
node.val = new_value
self.heap_dict[node.name] = new_value
self.sift_up(self.idx_of_element[node])
Expand Down
12 changes: 6 additions & 6 deletions data_structures/kd_tree/tests/test_kdtree.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,14 @@ def test_build_kdtree(num_points, cube_size, num_dimensions, depth, expected_res
assert kdtree is not None, "Expected a KDNode, got None"

# Check if root has correct dimensions
assert (
len(kdtree.point) == num_dimensions
), f"Expected point dimension {num_dimensions}, got {len(kdtree.point)}"
assert len(kdtree.point) == num_dimensions, (
f"Expected point dimension {num_dimensions}, got {len(kdtree.point)}"
)

# Check that the tree is balanced to some extent (simplistic check)
assert isinstance(
kdtree, KDNode
), f"Expected KDNode instance, got {type(kdtree)}"
assert isinstance(kdtree, KDNode), (
f"Expected KDNode instance, got {type(kdtree)}"
)


def test_nearest_neighbour_search():
Expand Down
24 changes: 12 additions & 12 deletions data_structures/suffix_tree/tests/test_suffix_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,37 +22,37 @@ def test_search_existing_patterns(self) -> None:
patterns = ["ana", "ban", "na"]
for pattern in patterns:
with self.subTest(pattern=pattern):
assert self.suffix_tree.search(
pattern
), f"Pattern '{pattern}' should be found."
assert self.suffix_tree.search(pattern), (
f"Pattern '{pattern}' should be found."
)

def test_search_non_existing_patterns(self) -> None:
"""Test searching for patterns that do not exist in the suffix tree."""
patterns = ["xyz", "apple", "cat"]
for pattern in patterns:
with self.subTest(pattern=pattern):
assert not self.suffix_tree.search(
pattern
), f"Pattern '{pattern}' should not be found."
assert not self.suffix_tree.search(pattern), (
f"Pattern '{pattern}' should not be found."
)

def test_search_empty_pattern(self) -> None:
"""Test searching for an empty pattern."""
assert self.suffix_tree.search(""), "An empty pattern should be found."

def test_search_full_text(self) -> None:
"""Test searching for the full text."""
assert self.suffix_tree.search(
self.text
), "The full text should be found in the suffix tree."
assert self.suffix_tree.search(self.text), (
"The full text should be found in the suffix tree."
)

def test_search_substrings(self) -> None:
"""Test searching for substrings of the full text."""
substrings = ["ban", "ana", "a", "na"]
for substring in substrings:
with self.subTest(substring=substring):
assert self.suffix_tree.search(
substring
), f"Substring '{substring}' should be found."
assert self.suffix_tree.search(substring), (
f"Substring '{substring}' should be found."
)


if __name__ == "__main__":
Expand Down
6 changes: 3 additions & 3 deletions dynamic_programming/climbing_stairs.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ def climb_stairs(number_of_steps: int) -> int:
...
AssertionError: number_of_steps needs to be positive integer, your input -7
"""
assert (
isinstance(number_of_steps, int) and number_of_steps > 0
), f"number_of_steps needs to be positive integer, your input {number_of_steps}"
assert isinstance(number_of_steps, int) and number_of_steps > 0, (
f"number_of_steps needs to be positive integer, your input {number_of_steps}"
)
if number_of_steps == 1:
return 1
previous, current = 1, 1
Expand Down
6 changes: 3 additions & 3 deletions dynamic_programming/iterating_through_submasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ def list_of_submasks(mask: int) -> list[int]:
"""

assert (
isinstance(mask, int) and mask > 0
), f"mask needs to be positive integer, your input {mask}"
assert isinstance(mask, int) and mask > 0, (
f"mask needs to be positive integer, your input {mask}"
)

"""
first submask iterated will be mask itself then operation will be performed
Expand Down
6 changes: 4 additions & 2 deletions dynamic_programming/longest_increasing_subsequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ def longest_subsequence(array: list[int]) -> list[int]: # This function is recu
[10, 22, 33, 41, 60, 80]
>>> longest_subsequence([4, 8, 7, 5, 1, 12, 2, 3, 9])
[1, 2, 3, 9]
>>> longest_subsequence([28, 26, 12, 23, 35, 39])
[12, 23, 35, 39]
>>> longest_subsequence([9, 8, 7, 6, 5, 7])
[8]
[5, 7]
>>> longest_subsequence([1, 1, 1])
[1, 1, 1]
>>> longest_subsequence([])
Expand All @@ -44,7 +46,7 @@ def longest_subsequence(array: list[int]) -> list[int]: # This function is recu
while not is_found and i < array_length:
if array[i] < pivot:
is_found = True
temp_array = [element for element in array[i:] if element >= array[i]]
temp_array = array[i:]
temp_array = longest_subsequence(temp_array)
if len(temp_array) > len(longest_subseq):
longest_subseq = temp_array
Expand Down
2 changes: 1 addition & 1 deletion dynamic_programming/matrix_chain_multiplication.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ def elapsed_time(msg: str) -> Iterator:

start = perf_counter_ns()
yield
print(f"Finished: {msg} in {(perf_counter_ns() - start) / 10 ** 9} seconds.")
print(f"Finished: {msg} in {(perf_counter_ns() - start) / 10**9} seconds.")


if __name__ == "__main__":
Expand Down
4 changes: 2 additions & 2 deletions machine_learning/linear_discriminant_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ def main():
user_count = valid_input(
input_type=int,
condition=lambda x: x > 0,
input_msg=(f"Enter The number of instances for class_{i+1}: "),
input_msg=(f"Enter The number of instances for class_{i + 1}: "),
err_msg="Number of instances should be positive!",
)
counts.append(user_count)
Expand All @@ -333,7 +333,7 @@ def main():
for a in range(n_classes):
user_mean = valid_input(
input_type=float,
input_msg=(f"Enter the value of mean for class_{a+1}: "),
input_msg=(f"Enter the value of mean for class_{a + 1}: "),
err_msg="This is an invalid value.",
)
user_means.append(user_mean)
Expand Down
6 changes: 2 additions & 4 deletions maths/dual_number_automatic_differentiation.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,8 @@ def __init__(self, real, rank):
self.duals = rank

def __repr__(self):
return (
f"{self.real}+"
f"{'+'.join(str(dual)+'E'+str(n+1)for n,dual in enumerate(self.duals))}"
)
s = "+".join(f"{dual}E{n}" for n, dual in enumerate(self.duals, 1))
return f"{self.real}+{s}"

def reduce(self):
cur = self.duals.copy()
Expand Down
4 changes: 3 additions & 1 deletion maths/max_sum_sliding_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,6 @@ def max_sum_in_array(array: list[int], k: int) -> int:
testmod()
array = [randint(-1000, 1000) for i in range(100)]
k = randint(0, 110)
print(f"The maximum sum of {k} consecutive elements is {max_sum_in_array(array,k)}")
print(
f"The maximum sum of {k} consecutive elements is {max_sum_in_array(array, k)}"
)
12 changes: 6 additions & 6 deletions maths/numerical_analysis/integration_by_simpson_approx.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,18 +88,18 @@ def simpson_integration(function, a: float, b: float, precision: int = 4) -> flo
AssertionError: precision should be positive integer your input : -1
"""
assert callable(
function
), f"the function(object) passed should be callable your input : {function}"
assert callable(function), (
f"the function(object) passed should be callable your input : {function}"
)
assert isinstance(a, (float, int)), f"a should be float or integer your input : {a}"
assert isinstance(function(a), (float, int)), (
"the function should return integer or float return type of your function, "
f"{type(a)}"
)
assert isinstance(b, (float, int)), f"b should be float or integer your input : {b}"
assert (
isinstance(precision, int) and precision > 0
), f"precision should be positive integer your input : {precision}"
assert isinstance(precision, int) and precision > 0, (
f"precision should be positive integer your input : {precision}"
)

# just applying the formula of simpson for approximate integration written in
# mentioned article in first comment of this file and above this function
Expand Down
12 changes: 6 additions & 6 deletions maths/prime_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,12 @@ def test_primes(self):
def test_not_primes(self):
with pytest.raises(ValueError):
is_prime(-19)
assert not is_prime(
0
), "Zero doesn't have any positive factors, primes must have exactly two."
assert not is_prime(
1
), "One only has 1 positive factor, primes must have exactly two."
assert not is_prime(0), (
"Zero doesn't have any positive factors, primes must have exactly two."
)
assert not is_prime(1), (
"One only has 1 positive factor, primes must have exactly two."
)
assert not is_prime(2 * 2)
assert not is_prime(2 * 3)
assert not is_prime(3 * 3)
Expand Down
Loading

0 comments on commit e27c028

Please sign in to comment.