Skip to content

Commit 49bffb8

Browse files
Merge branch 'TheAlgorithms:master' into master
2 parents 6ab71c2 + 0c8cf8e commit 49bffb8

38 files changed

+428
-121
lines changed

.pre-commit-config.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,20 @@ repos:
1616
- id: auto-walrus
1717

1818
- repo: https://github.com/astral-sh/ruff-pre-commit
19-
rev: v0.9.3
19+
rev: v0.11.2
2020
hooks:
2121
- id: ruff
2222
- id: ruff-format
2323

2424
- repo: https://github.com/codespell-project/codespell
25-
rev: v2.4.0
25+
rev: v2.4.1
2626
hooks:
2727
- id: codespell
2828
additional_dependencies:
2929
- tomli
3030

3131
- repo: https://github.com/tox-dev/pyproject-fmt
32-
rev: "v2.5.0"
32+
rev: "v2.5.1"
3333
hooks:
3434
- id: pyproject-fmt
3535

@@ -42,12 +42,12 @@ repos:
4242
pass_filenames: false
4343

4444
- repo: https://github.com/abravalheri/validate-pyproject
45-
rev: v0.23
45+
rev: v0.24.1
4646
hooks:
4747
- id: validate-pyproject
4848

4949
- repo: https://github.com/pre-commit/mirrors-mypy
50-
rev: v1.14.1
50+
rev: v1.15.0
5151
hooks:
5252
- id: mypy
5353
args:

DIRECTORY.md

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -275,20 +275,21 @@
275275
* [Singly Linked List](data_structures/linked_list/singly_linked_list.py)
276276
* [Skip List](data_structures/linked_list/skip_list.py)
277277
* [Swap Nodes](data_structures/linked_list/swap_nodes.py)
278-
* Queue
279-
* [Circular Queue](data_structures/queue/circular_queue.py)
280-
* [Circular Queue Linked List](data_structures/queue/circular_queue_linked_list.py)
281-
* [Double Ended Queue](data_structures/queue/double_ended_queue.py)
282-
* [Linked Queue](data_structures/queue/linked_queue.py)
283-
* [Priority Queue Using List](data_structures/queue/priority_queue_using_list.py)
284-
* [Queue By List](data_structures/queue/queue_by_list.py)
285-
* [Queue By Two Stacks](data_structures/queue/queue_by_two_stacks.py)
286-
* [Queue On Pseudo Stack](data_structures/queue/queue_on_pseudo_stack.py)
278+
* Queues
279+
* [Circular Queue](data_structures/queues/circular_queue.py)
280+
* [Circular Queue Linked List](data_structures/queues/circular_queue_linked_list.py)
281+
* [Double Ended Queue](data_structures/queues/double_ended_queue.py)
282+
* [Linked Queue](data_structures/queues/linked_queue.py)
283+
* [Priority Queue Using List](data_structures/queues/priority_queue_using_list.py)
284+
* [Queue By List](data_structures/queues/queue_by_list.py)
285+
* [Queue By Two Stacks](data_structures/queues/queue_by_two_stacks.py)
286+
* [Queue On Pseudo Stack](data_structures/queues/queue_on_pseudo_stack.py)
287287
* Stacks
288288
* [Balanced Parentheses](data_structures/stacks/balanced_parentheses.py)
289289
* [Dijkstras Two Stack Algorithm](data_structures/stacks/dijkstras_two_stack_algorithm.py)
290290
* [Infix To Postfix Conversion](data_structures/stacks/infix_to_postfix_conversion.py)
291291
* [Infix To Prefix Conversion](data_structures/stacks/infix_to_prefix_conversion.py)
292+
* [Largest Rectangle Histogram](data_structures/stacks/largest_rectangle_histogram.py)
292293
* [Lexicographical Numbers](data_structures/stacks/lexicographical_numbers.py)
293294
* [Next Greater Element](data_structures/stacks/next_greater_element.py)
294295
* [Postfix Evaluation](data_structures/stacks/postfix_evaluation.py)
@@ -395,6 +396,7 @@
395396
* [Minimum Tickets Cost](dynamic_programming/minimum_tickets_cost.py)
396397
* [Optimal Binary Search Tree](dynamic_programming/optimal_binary_search_tree.py)
397398
* [Palindrome Partitioning](dynamic_programming/palindrome_partitioning.py)
399+
* [Range Sum Query](dynamic_programming/range_sum_query.py)
398400
* [Regex Match](dynamic_programming/regex_match.py)
399401
* [Rod Cutting](dynamic_programming/rod_cutting.py)
400402
* [Smith Waterman](dynamic_programming/smith_waterman.py)
@@ -608,6 +610,7 @@
608610
* [Mfcc](machine_learning/mfcc.py)
609611
* [Multilayer Perceptron Classifier](machine_learning/multilayer_perceptron_classifier.py)
610612
* [Polynomial Regression](machine_learning/polynomial_regression.py)
613+
* [Principle Component Analysis](machine_learning/principle_component_analysis.py)
611614
* [Scoring Functions](machine_learning/scoring_functions.py)
612615
* [Self Organizing Map](machine_learning/self_organizing_map.py)
613616
* [Sequential Minimum Optimization](machine_learning/sequential_minimum_optimization.py)

backtracking/n_queens.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,28 @@ def is_safe(board: list[list[int]], row: int, column: int) -> bool:
2727
2828
>>> is_safe([[0, 0, 0], [0, 0, 0], [0, 0, 0]], 1, 1)
2929
True
30+
>>> is_safe([[0, 1, 0], [0, 0, 0], [0, 0, 0]], 1, 1)
31+
False
3032
>>> is_safe([[1, 0, 0], [0, 0, 0], [0, 0, 0]], 1, 1)
3133
False
34+
>>> is_safe([[0, 0, 1], [0, 0, 0], [0, 0, 0]], 1, 1)
35+
False
3236
"""
3337

3438
n = len(board) # Size of the board
3539

36-
# Check if there is any queen in the same row, column,
37-
# left upper diagonal, and right upper diagonal
40+
# Check if there is any queen in the same upper column,
41+
# left upper diagonal and right upper diagonal
3842
return (
39-
all(board[i][j] != 1 for i, j in zip(range(row, -1, -1), range(column, n)))
43+
all(board[i][j] != 1 for i, j in zip(range(row), [column] * row))
44+
and all(
45+
board[i][j] != 1
46+
for i, j in zip(range(row - 1, -1, -1), range(column - 1, -1, -1))
47+
)
4048
and all(
41-
board[i][j] != 1 for i, j in zip(range(row, -1, -1), range(column, -1, -1))
49+
board[i][j] != 1
50+
for i, j in zip(range(row - 1, -1, -1), range(column + 1, n))
4251
)
43-
and all(board[i][j] != 1 for i, j in zip(range(row, n), range(column, n)))
44-
and all(board[i][j] != 1 for i, j in zip(range(row, n), range(column, -1, -1)))
4552
)
4653

4754

conversions/prefix_conversions_string.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class SIUnit(Enum):
5353
yocto = -24
5454

5555
@classmethod
56-
def get_positive(cls: type[T]) -> dict:
56+
def get_positive(cls) -> dict:
5757
"""
5858
Returns a dictionary with only the elements of this enum
5959
that has a positive value
@@ -68,7 +68,7 @@ def get_positive(cls: type[T]) -> dict:
6868
return {unit.name: unit.value for unit in cls if unit.value > 0}
6969

7070
@classmethod
71-
def get_negative(cls: type[T]) -> dict:
71+
def get_negative(cls) -> dict:
7272
"""
7373
Returns a dictionary with only the elements of this enum
7474
that has a negative value

data_structures/arrays/prefix_sum.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,29 @@ def get_sum(self, start: int, end: int) -> int:
3030
5
3131
>>> PrefixSum([1,2,3]).get_sum(2, 2)
3232
3
33+
>>> PrefixSum([]).get_sum(0, 0)
34+
Traceback (most recent call last):
35+
...
36+
ValueError: The array is empty.
37+
>>> PrefixSum([1,2,3]).get_sum(-1, 2)
38+
Traceback (most recent call last):
39+
...
40+
ValueError: Invalid range specified.
3341
>>> PrefixSum([1,2,3]).get_sum(2, 3)
3442
Traceback (most recent call last):
3543
...
36-
IndexError: list index out of range
44+
ValueError: Invalid range specified.
45+
>>> PrefixSum([1,2,3]).get_sum(2, 1)
46+
Traceback (most recent call last):
47+
...
48+
ValueError: Invalid range specified.
3749
"""
50+
if not self.prefix_sum:
51+
raise ValueError("The array is empty.")
52+
53+
if start < 0 or end >= len(self.prefix_sum) or start > end:
54+
raise ValueError("Invalid range specified.")
55+
3856
if start == 0:
3957
return self.prefix_sum[end]
4058

data_structures/arrays/sudoku_solver.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def parse_grid(grid):
5454
return False if a contradiction is detected.
5555
"""
5656
## To start, every square can be any digit; then assign values from the grid.
57-
values = {s: digits for s in squares}
57+
values = dict.fromkeys(squares, digits)
5858
for s, d in grid_values(grid).items():
5959
if d in digits and not assign(values, s, d):
6060
return False ## (Fail if we can't assign d to square s.)
@@ -203,7 +203,7 @@ def random_puzzle(assignments=17):
203203
Note the resulting puzzle is not guaranteed to be solvable, but empirically
204204
about 99.8% of them are solvable. Some have multiple solutions.
205205
"""
206-
values = {s: digits for s in squares}
206+
values = dict.fromkeys(squares, digits)
207207
for s in shuffled(squares):
208208
if not assign(values, s, random.choice(values[s])):
209209
break

data_structures/linked_list/doubly_linked_list_two.py

Lines changed: 46 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,19 @@
99
Delete operation is more efficient
1010
"""
1111

12+
from dataclasses import dataclass
13+
from typing import Self
1214

15+
16+
@dataclass
1317
class Node:
14-
def __init__(self, data: int, previous=None, next_node=None):
15-
self.data = data
16-
self.previous = previous
17-
self.next = next_node
18+
data: int
19+
previous: Self | None = None
20+
next: Self | None = None
1821

1922
def __str__(self) -> str:
2023
return f"{self.data}"
2124

22-
def get_data(self) -> int:
23-
return self.data
24-
25-
def get_next(self):
26-
return self.next
27-
28-
def get_previous(self):
29-
return self.previous
30-
3125

3226
class LinkedListIterator:
3327
def __init__(self, head):
@@ -40,43 +34,43 @@ def __next__(self):
4034
if not self.current:
4135
raise StopIteration
4236
else:
43-
value = self.current.get_data()
44-
self.current = self.current.get_next()
37+
value = self.current.data
38+
self.current = self.current.next
4539
return value
4640

4741

42+
@dataclass
4843
class LinkedList:
49-
def __init__(self):
50-
self.head = None # First node in list
51-
self.tail = None # Last node in list
44+
head: Node | None = None # First node in list
45+
tail: Node | None = None # Last node in list
5246

5347
def __str__(self):
5448
current = self.head
5549
nodes = []
5650
while current is not None:
57-
nodes.append(current.get_data())
58-
current = current.get_next()
51+
nodes.append(current.data)
52+
current = current.next
5953
return " ".join(str(node) for node in nodes)
6054

6155
def __contains__(self, value: int):
6256
current = self.head
6357
while current:
64-
if current.get_data() == value:
58+
if current.data == value:
6559
return True
66-
current = current.get_next()
60+
current = current.next
6761
return False
6862

6963
def __iter__(self):
7064
return LinkedListIterator(self.head)
7165

7266
def get_head_data(self):
7367
if self.head:
74-
return self.head.get_data()
68+
return self.head.data
7569
return None
7670

7771
def get_tail_data(self):
7872
if self.tail:
79-
return self.tail.get_data()
73+
return self.tail.data
8074
return None
8175

8276
def set_head(self, node: Node) -> None:
@@ -87,8 +81,9 @@ def set_head(self, node: Node) -> None:
8781
self.insert_before_node(self.head, node)
8882

8983
def set_tail(self, node: Node) -> None:
90-
if self.head is None:
91-
self.set_head(node)
84+
if self.tail is None:
85+
self.head = node
86+
self.tail = node
9287
else:
9388
self.insert_after_node(self.tail, node)
9489

@@ -103,7 +98,7 @@ def insert_before_node(self, node: Node, node_to_insert: Node) -> None:
10398
node_to_insert.next = node
10499
node_to_insert.previous = node.previous
105100

106-
if node.get_previous() is None:
101+
if node.previous is None:
107102
self.head = node_to_insert
108103
else:
109104
node.previous.next = node_to_insert
@@ -114,7 +109,7 @@ def insert_after_node(self, node: Node, node_to_insert: Node) -> None:
114109
node_to_insert.previous = node
115110
node_to_insert.next = node.next
116111

117-
if node.get_next() is None:
112+
if node.next is None:
118113
self.tail = node_to_insert
119114
else:
120115
node.next.previous = node_to_insert
@@ -131,32 +126,32 @@ def insert_at_position(self, position: int, value: int) -> None:
131126
return
132127
current_position += 1
133128
node = node.next
134-
self.insert_after_node(self.tail, new_node)
129+
self.set_tail(new_node)
135130

136131
def get_node(self, item: int) -> Node:
137132
node = self.head
138133
while node:
139-
if node.get_data() == item:
134+
if node.data == item:
140135
return node
141-
node = node.get_next()
136+
node = node.next
142137
raise Exception("Node not found")
143138

144139
def delete_value(self, value):
145140
if (node := self.get_node(value)) is not None:
146141
if node == self.head:
147-
self.head = self.head.get_next()
142+
self.head = self.head.next
148143

149144
if node == self.tail:
150-
self.tail = self.tail.get_previous()
145+
self.tail = self.tail.previous
151146

152147
self.remove_node_pointers(node)
153148

154149
@staticmethod
155150
def remove_node_pointers(node: Node) -> None:
156-
if node.get_next():
151+
if node.next:
157152
node.next.previous = node.previous
158153

159-
if node.get_previous():
154+
if node.previous:
160155
node.previous.next = node.next
161156

162157
node.next = None
@@ -241,6 +236,22 @@ def create_linked_list() -> None:
241236
7
242237
8
243238
9
239+
>>> linked_list = LinkedList()
240+
>>> linked_list.insert_at_position(position=1, value=10)
241+
>>> str(linked_list)
242+
'10'
243+
>>> linked_list.insert_at_position(position=2, value=20)
244+
>>> str(linked_list)
245+
'10 20'
246+
>>> linked_list.insert_at_position(position=1, value=30)
247+
>>> str(linked_list)
248+
'30 10 20'
249+
>>> linked_list.insert_at_position(position=3, value=40)
250+
>>> str(linked_list)
251+
'30 10 40 20'
252+
>>> linked_list.insert_at_position(position=5, value=50)
253+
>>> str(linked_list)
254+
'30 10 40 20 50'
244255
"""
245256

246257

data_structures/linked_list/from_sequence.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Recursive Prorgam to create a Linked List from a sequence and
1+
# Recursive Program to create a Linked List from a sequence and
22
# print a string representation of it.
33

44

File renamed without changes.

0 commit comments

Comments
 (0)