Skip to content

Commit 8704157

Browse files
authored
Merge branch 'TheAlgorithms:master' into master
2 parents 1fab302 + c16d2f8 commit 8704157

File tree

2 files changed

+191
-51
lines changed

2 files changed

+191
-51
lines changed

Diff for: backtracking/rat_in_maze.py

+130-51
Original file line numberDiff line numberDiff line change
@@ -1,118 +1,197 @@
11
from __future__ import annotations
22

33

4-
def solve_maze(maze: list[list[int]]) -> bool:
4+
def solve_maze(
5+
maze: list[list[int]],
6+
source_row: int,
7+
source_column: int,
8+
destination_row: int,
9+
destination_column: int,
10+
) -> list[list[int]]:
511
"""
612
This method solves the "rat in maze" problem.
7-
In this problem we have some n by n matrix, a start point and an end point.
8-
We want to go from the start to the end. In this matrix zeroes represent walls
9-
and ones paths we can use.
1013
Parameters :
11-
maze(2D matrix) : maze
14+
- maze: A two dimensional matrix of zeros and ones.
15+
- source_row: The row index of the starting point.
16+
- source_column: The column index of the starting point.
17+
- destination_row: The row index of the destination point.
18+
- destination_column: The column index of the destination point.
1219
Returns:
13-
Return: True if the maze has a solution or False if it does not.
20+
- solution: A 2D matrix representing the solution path if it exists.
21+
Raises:
22+
- ValueError: If no solution exists or if the source or
23+
destination coordinates are invalid.
24+
Description:
25+
This method navigates through a maze represented as an n by n matrix,
26+
starting from a specified source cell and
27+
aiming to reach a destination cell.
28+
The maze consists of walls (1s) and open paths (0s).
29+
By providing custom row and column values, the source and destination
30+
cells can be adjusted.
1431
>>> maze = [[0, 1, 0, 1, 1],
1532
... [0, 0, 0, 0, 0],
1633
... [1, 0, 1, 0, 1],
1734
... [0, 0, 1, 0, 0],
1835
... [1, 0, 0, 1, 0]]
19-
>>> solve_maze(maze)
20-
[1, 0, 0, 0, 0]
21-
[1, 1, 1, 1, 0]
22-
[0, 0, 0, 1, 0]
23-
[0, 0, 0, 1, 1]
24-
[0, 0, 0, 0, 1]
25-
True
36+
>>> solve_maze(maze,0,0,len(maze)-1,len(maze)-1) # doctest: +NORMALIZE_WHITESPACE
37+
[[0, 1, 1, 1, 1],
38+
[0, 0, 0, 0, 1],
39+
[1, 1, 1, 0, 1],
40+
[1, 1, 1, 0, 0],
41+
[1, 1, 1, 1, 0]]
42+
43+
Note:
44+
In the output maze, the zeros (0s) represent one of the possible
45+
paths from the source to the destination.
2646
2747
>>> maze = [[0, 1, 0, 1, 1],
2848
... [0, 0, 0, 0, 0],
2949
... [0, 0, 0, 0, 1],
3050
... [0, 0, 0, 0, 0],
3151
... [0, 0, 0, 0, 0]]
32-
>>> solve_maze(maze)
33-
[1, 0, 0, 0, 0]
34-
[1, 0, 0, 0, 0]
35-
[1, 0, 0, 0, 0]
36-
[1, 0, 0, 0, 0]
37-
[1, 1, 1, 1, 1]
38-
True
52+
>>> solve_maze(maze,0,0,len(maze)-1,len(maze)-1) # doctest: +NORMALIZE_WHITESPACE
53+
[[0, 1, 1, 1, 1],
54+
[0, 1, 1, 1, 1],
55+
[0, 1, 1, 1, 1],
56+
[0, 1, 1, 1, 1],
57+
[0, 0, 0, 0, 0]]
3958
4059
>>> maze = [[0, 0, 0],
4160
... [0, 1, 0],
4261
... [1, 0, 0]]
43-
>>> solve_maze(maze)
44-
[1, 1, 1]
45-
[0, 0, 1]
46-
[0, 0, 1]
47-
True
62+
>>> solve_maze(maze,0,0,len(maze)-1,len(maze)-1) # doctest: +NORMALIZE_WHITESPACE
63+
[[0, 0, 0],
64+
[1, 1, 0],
65+
[1, 1, 0]]
4866
49-
>>> maze = [[0, 1, 0],
67+
>>> maze = [[1, 0, 0],
5068
... [0, 1, 0],
5169
... [1, 0, 0]]
52-
>>> solve_maze(maze)
53-
No solution exists!
54-
False
70+
>>> solve_maze(maze,0,1,len(maze)-1,len(maze)-1) # doctest: +NORMALIZE_WHITESPACE
71+
[[1, 0, 0],
72+
[1, 1, 0],
73+
[1, 1, 0]]
74+
75+
>>> maze = [[1, 1, 0, 0, 1, 0, 0, 1],
76+
... [1, 0, 1, 0, 0, 1, 1, 1],
77+
... [0, 1, 0, 1, 0, 0, 1, 0],
78+
... [1, 1, 1, 0, 0, 1, 0, 1],
79+
... [0, 1, 0, 0, 1, 0, 1, 1],
80+
... [0, 0, 0, 1, 1, 1, 0, 1],
81+
... [0, 1, 0, 1, 0, 1, 1, 1],
82+
... [1, 1, 0, 0, 0, 0, 0, 1]]
83+
>>> solve_maze(maze,0,2,len(maze)-1,2) # doctest: +NORMALIZE_WHITESPACE
84+
[[1, 1, 0, 0, 1, 1, 1, 1],
85+
[1, 1, 1, 0, 0, 1, 1, 1],
86+
[1, 1, 1, 1, 0, 1, 1, 1],
87+
[1, 1, 1, 0, 0, 1, 1, 1],
88+
[1, 1, 0, 0, 1, 1, 1, 1],
89+
[1, 1, 0, 1, 1, 1, 1, 1],
90+
[1, 1, 0, 1, 1, 1, 1, 1],
91+
[1, 1, 0, 1, 1, 1, 1, 1]]
92+
>>> maze = [[1, 0, 0],
93+
... [0, 1, 1],
94+
... [1, 0, 1]]
95+
>>> solve_maze(maze,0,1,len(maze)-1,len(maze)-1)
96+
Traceback (most recent call last):
97+
...
98+
ValueError: No solution exists!
99+
100+
>>> maze = [[0, 0],
101+
... [1, 1]]
102+
>>> solve_maze(maze,0,0,len(maze)-1,len(maze)-1)
103+
Traceback (most recent call last):
104+
...
105+
ValueError: No solution exists!
55106
56107
>>> maze = [[0, 1],
57108
... [1, 0]]
58-
>>> solve_maze(maze)
59-
No solution exists!
60-
False
109+
>>> solve_maze(maze,2,0,len(maze)-1,len(maze)-1)
110+
Traceback (most recent call last):
111+
...
112+
ValueError: Invalid source or destination coordinates
113+
114+
>>> maze = [[1, 0, 0],
115+
... [0, 1, 0],
116+
... [1, 0, 0]]
117+
>>> solve_maze(maze,0,1,len(maze),len(maze)-1)
118+
Traceback (most recent call last):
119+
...
120+
ValueError: Invalid source or destination coordinates
61121
"""
62122
size = len(maze)
123+
# Check if source and destination coordinates are Invalid.
124+
if not (0 <= source_row <= size - 1 and 0 <= source_column <= size - 1) or (
125+
not (0 <= destination_row <= size - 1 and 0 <= destination_column <= size - 1)
126+
):
127+
raise ValueError("Invalid source or destination coordinates")
63128
# We need to create solution object to save path.
64-
solutions = [[0 for _ in range(size)] for _ in range(size)]
65-
solved = run_maze(maze, 0, 0, solutions)
129+
solutions = [[1 for _ in range(size)] for _ in range(size)]
130+
solved = run_maze(
131+
maze, source_row, source_column, destination_row, destination_column, solutions
132+
)
66133
if solved:
67-
print("\n".join(str(row) for row in solutions))
134+
return solutions
68135
else:
69-
print("No solution exists!")
70-
return solved
136+
raise ValueError("No solution exists!")
71137

72138

73-
def run_maze(maze: list[list[int]], i: int, j: int, solutions: list[list[int]]) -> bool:
139+
def run_maze(
140+
maze: list[list[int]],
141+
i: int,
142+
j: int,
143+
destination_row: int,
144+
destination_column: int,
145+
solutions: list[list[int]],
146+
) -> bool:
74147
"""
75148
This method is recursive starting from (i, j) and going in one of four directions:
76149
up, down, left, right.
77150
If a path is found to destination it returns True otherwise it returns False.
78-
Parameters:
79-
maze(2D matrix) : maze
151+
Parameters
152+
maze: A two dimensional matrix of zeros and ones.
80153
i, j : coordinates of matrix
81-
solutions(2D matrix) : solutions
154+
solutions: A two dimensional matrix of solutions.
82155
Returns:
83156
Boolean if path is found True, Otherwise False.
84157
"""
85158
size = len(maze)
86159
# Final check point.
87-
if i == j == (size - 1):
88-
solutions[i][j] = 1
160+
if i == destination_row and j == destination_column and maze[i][j] == 0:
161+
solutions[i][j] = 0
89162
return True
90163

91164
lower_flag = (not i < 0) and (not j < 0) # Check lower bounds
92165
upper_flag = (i < size) and (j < size) # Check upper bounds
93166

94167
if lower_flag and upper_flag:
95168
# check for already visited and block points.
96-
block_flag = (not solutions[i][j]) and (not maze[i][j])
169+
block_flag = (solutions[i][j]) and (not maze[i][j])
97170
if block_flag:
98171
# check visited
99-
solutions[i][j] = 1
172+
solutions[i][j] = 0
100173

101174
# check for directions
102175
if (
103-
run_maze(maze, i + 1, j, solutions)
104-
or run_maze(maze, i, j + 1, solutions)
105-
or run_maze(maze, i - 1, j, solutions)
106-
or run_maze(maze, i, j - 1, solutions)
176+
run_maze(maze, i + 1, j, destination_row, destination_column, solutions)
177+
or run_maze(
178+
maze, i, j + 1, destination_row, destination_column, solutions
179+
)
180+
or run_maze(
181+
maze, i - 1, j, destination_row, destination_column, solutions
182+
)
183+
or run_maze(
184+
maze, i, j - 1, destination_row, destination_column, solutions
185+
)
107186
):
108187
return True
109188

110-
solutions[i][j] = 0
189+
solutions[i][j] = 1
111190
return False
112191
return False
113192

114193

115194
if __name__ == "__main__":
116195
import doctest
117196

118-
doctest.testmod()
197+
doctest.testmod(optionflags=doctest.NORMALIZE_WHITESPACE)

Diff for: data_structures/arrays/median_two_array.py

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
"""
2+
https://www.enjoyalgorithms.com/blog/median-of-two-sorted-arrays
3+
"""
4+
5+
6+
def find_median_sorted_arrays(nums1: list[int], nums2: list[int]) -> float:
7+
"""
8+
Find the median of two arrays.
9+
10+
Args:
11+
nums1: The first array.
12+
nums2: The second array.
13+
14+
Returns:
15+
The median of the two arrays.
16+
17+
Examples:
18+
>>> find_median_sorted_arrays([1, 3], [2])
19+
2.0
20+
21+
>>> find_median_sorted_arrays([1, 2], [3, 4])
22+
2.5
23+
24+
>>> find_median_sorted_arrays([0, 0], [0, 0])
25+
0.0
26+
27+
>>> find_median_sorted_arrays([], [])
28+
Traceback (most recent call last):
29+
...
30+
ValueError: Both input arrays are empty.
31+
32+
>>> find_median_sorted_arrays([], [1])
33+
1.0
34+
35+
>>> find_median_sorted_arrays([-1000], [1000])
36+
0.0
37+
38+
>>> find_median_sorted_arrays([-1.1, -2.2], [-3.3, -4.4])
39+
-2.75
40+
"""
41+
if not nums1 and not nums2:
42+
raise ValueError("Both input arrays are empty.")
43+
44+
# Merge the arrays into a single sorted array.
45+
merged = sorted(nums1 + nums2)
46+
total = len(merged)
47+
48+
if total % 2 == 1: # If the total number of elements is odd
49+
return float(merged[total // 2]) # then return the middle element
50+
51+
# If the total number of elements is even, calculate
52+
# the average of the two middle elements as the median.
53+
middle1 = merged[total // 2 - 1]
54+
middle2 = merged[total // 2]
55+
return (float(middle1) + float(middle2)) / 2.0
56+
57+
58+
if __name__ == "__main__":
59+
import doctest
60+
61+
doctest.testmod()

0 commit comments

Comments
 (0)