Skip to content

Commit 26df1fc

Browse files
authored
Merge branch 'TheAlgorithms:master' into time_period_simple_pendulum
2 parents 7cf42d9 + 76acc6d commit 26df1fc

File tree

7 files changed

+215
-64
lines changed

7 files changed

+215
-64
lines changed

.github/CODEOWNERS

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
# Order is important. The last matching pattern has the most precedence.
99

10-
/.* @cclauss @dhruvmanila
10+
/.* @cclauss
1111

1212
# /arithmetic_analysis/
1313

greedy_methods/fractional_knapsack.py

+24
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,30 @@ def frac_knapsack(vl, wt, w, n):
66
"""
77
>>> frac_knapsack([60, 100, 120], [10, 20, 30], 50, 3)
88
240.0
9+
>>> frac_knapsack([10, 40, 30, 50], [5, 4, 6, 3], 10, 4)
10+
105.0
11+
>>> frac_knapsack([10, 40, 30, 50], [5, 4, 6, 3], 8, 4)
12+
95.0
13+
>>> frac_knapsack([10, 40, 30, 50], [5, 4, 6], 8, 4)
14+
60.0
15+
>>> frac_knapsack([10, 40, 30], [5, 4, 6, 3], 8, 4)
16+
60.0
17+
>>> frac_knapsack([10, 40, 30, 50], [5, 4, 6, 3], 0, 4)
18+
0
19+
>>> frac_knapsack([10, 40, 30, 50], [5, 4, 6, 3], 8, 0)
20+
95.0
21+
>>> frac_knapsack([10, 40, 30, 50], [5, 4, 6, 3], -8, 4)
22+
0
23+
>>> frac_knapsack([10, 40, 30, 50], [5, 4, 6, 3], 8, -4)
24+
95.0
25+
>>> frac_knapsack([10, 40, 30, 50], [5, 4, 6, 3], 800, 4)
26+
130
27+
>>> frac_knapsack([10, 40, 30, 50], [5, 4, 6, 3], 8, 400)
28+
95.0
29+
>>> frac_knapsack("ABCD", [5, 4, 6, 3], 8, 400)
30+
Traceback (most recent call last):
31+
...
32+
TypeError: unsupported operand type(s) for /: 'str' and 'int'
933
"""
1034

1135
r = sorted(zip(vl, wt), key=lambda x: x[0] / x[1], reverse=True)

maths/binomial_coefficient.py

+44-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,48 @@
11
def binomial_coefficient(n: int, r: int) -> int:
22
"""
3-
Find binomial coefficient using pascals triangle.
3+
Find binomial coefficient using Pascal's triangle.
4+
5+
Calculate C(n, r) using Pascal's triangle.
6+
7+
:param n: The total number of items.
8+
:param r: The number of items to choose.
9+
:return: The binomial coefficient C(n, r).
410
511
>>> binomial_coefficient(10, 5)
612
252
13+
>>> binomial_coefficient(10, 0)
14+
1
15+
>>> binomial_coefficient(0, 10)
16+
1
17+
>>> binomial_coefficient(10, 10)
18+
1
19+
>>> binomial_coefficient(5, 2)
20+
10
21+
>>> binomial_coefficient(5, 6)
22+
0
23+
>>> binomial_coefficient(3, 5)
24+
0
25+
>>> binomial_coefficient(-2, 3)
26+
Traceback (most recent call last):
27+
...
28+
ValueError: n and r must be non-negative integers
29+
>>> binomial_coefficient(5, -1)
30+
Traceback (most recent call last):
31+
...
32+
ValueError: n and r must be non-negative integers
33+
>>> binomial_coefficient(10.1, 5)
34+
Traceback (most recent call last):
35+
...
36+
TypeError: 'float' object cannot be interpreted as an integer
37+
>>> binomial_coefficient(10, 5.1)
38+
Traceback (most recent call last):
39+
...
40+
TypeError: 'float' object cannot be interpreted as an integer
741
"""
42+
if n < 0 or r < 0:
43+
raise ValueError("n and r must be non-negative integers")
44+
if 0 in (n, r):
45+
return 1
846
c = [0 for i in range(r + 1)]
947
# nc0 = 1
1048
c[0] = 1
@@ -17,4 +55,8 @@ def binomial_coefficient(n: int, r: int) -> int:
1755
return c[r]
1856

1957

20-
print(binomial_coefficient(n=10, r=5))
58+
if __name__ == "__main__":
59+
from doctest import testmod
60+
61+
testmod()
62+
print(binomial_coefficient(n=10, r=5))

networking_flow/ford_fulkerson.py

+80-29
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,95 @@
1-
# Ford-Fulkerson Algorithm for Maximum Flow Problem
21
"""
2+
Ford-Fulkerson Algorithm for Maximum Flow Problem
3+
* https://en.wikipedia.org/wiki/Ford%E2%80%93Fulkerson_algorithm
4+
35
Description:
4-
(1) Start with initial flow as 0;
5-
(2) Choose augmenting path from source to sink and add path to flow;
6+
(1) Start with initial flow as 0
7+
(2) Choose the augmenting path from source to sink and add the path to flow
68
"""
9+
graph = [
10+
[0, 16, 13, 0, 0, 0],
11+
[0, 0, 10, 12, 0, 0],
12+
[0, 4, 0, 0, 14, 0],
13+
[0, 0, 9, 0, 0, 20],
14+
[0, 0, 0, 7, 0, 4],
15+
[0, 0, 0, 0, 0, 0],
16+
]
17+
18+
19+
def breadth_first_search(graph: list, source: int, sink: int, parents: list) -> bool:
20+
"""
21+
This function returns True if there is a node that has not iterated.
22+
23+
Args:
24+
graph: Adjacency matrix of graph
25+
source: Source
26+
sink: Sink
27+
parents: Parent list
28+
29+
Returns:
30+
True if there is a node that has not iterated.
731
32+
>>> breadth_first_search(graph, 0, 5, [-1, -1, -1, -1, -1, -1])
33+
True
34+
>>> breadth_first_search(graph, 0, 6, [-1, -1, -1, -1, -1, -1])
35+
Traceback (most recent call last):
36+
...
37+
IndexError: list index out of range
38+
"""
39+
visited = [False] * len(graph) # Mark all nodes as not visited
40+
queue = [] # breadth-first search queue
841

9-
def bfs(graph, s, t, parent):
10-
# Return True if there is node that has not iterated.
11-
visited = [False] * len(graph)
12-
queue = []
13-
queue.append(s)
14-
visited[s] = True
42+
# Source node
43+
queue.append(source)
44+
visited[source] = True
1545

1646
while queue:
17-
u = queue.pop(0)
18-
for ind in range(len(graph[u])):
19-
if visited[ind] is False and graph[u][ind] > 0:
47+
u = queue.pop(0) # Pop the front node
48+
# Traverse all adjacent nodes of u
49+
for ind, node in enumerate(graph[u]):
50+
if visited[ind] is False and node > 0:
2051
queue.append(ind)
2152
visited[ind] = True
22-
parent[ind] = u
53+
parents[ind] = u
54+
return visited[sink]
2355

24-
return visited[t]
2556

57+
def ford_fulkerson(graph: list, source: int, sink: int) -> int:
58+
"""
59+
This function returns the maximum flow from source to sink in the given graph.
2660
27-
def ford_fulkerson(graph, source, sink):
28-
# This array is filled by BFS and to store path
61+
CAUTION: This function changes the given graph.
62+
63+
Args:
64+
graph: Adjacency matrix of graph
65+
source: Source
66+
sink: Sink
67+
68+
Returns:
69+
Maximum flow
70+
71+
>>> test_graph = [
72+
... [0, 16, 13, 0, 0, 0],
73+
... [0, 0, 10, 12, 0, 0],
74+
... [0, 4, 0, 0, 14, 0],
75+
... [0, 0, 9, 0, 0, 20],
76+
... [0, 0, 0, 7, 0, 4],
77+
... [0, 0, 0, 0, 0, 0],
78+
... ]
79+
>>> ford_fulkerson(test_graph, 0, 5)
80+
23
81+
"""
82+
# This array is filled by breadth-first search and to store path
2983
parent = [-1] * (len(graph))
3084
max_flow = 0
31-
while bfs(graph, source, sink, parent):
32-
path_flow = float("Inf")
85+
86+
# While there is a path from source to sink
87+
while breadth_first_search(graph, source, sink, parent):
88+
path_flow = int(1e9) # Infinite value
3389
s = sink
3490

3591
while s != source:
36-
# Find the minimum value in select path
92+
# Find the minimum value in the selected path
3793
path_flow = min(path_flow, graph[parent[s]][s])
3894
s = parent[s]
3995

@@ -45,17 +101,12 @@ def ford_fulkerson(graph, source, sink):
45101
graph[u][v] -= path_flow
46102
graph[v][u] += path_flow
47103
v = parent[v]
104+
48105
return max_flow
49106

50107

51-
graph = [
52-
[0, 16, 13, 0, 0, 0],
53-
[0, 0, 10, 12, 0, 0],
54-
[0, 4, 0, 0, 14, 0],
55-
[0, 0, 9, 0, 0, 20],
56-
[0, 0, 0, 7, 0, 4],
57-
[0, 0, 0, 0, 0, 0],
58-
]
108+
if __name__ == "__main__":
109+
from doctest import testmod
59110

60-
source, sink = 0, 5
61-
print(ford_fulkerson(graph, source, sink))
111+
testmod()
112+
print(f"{ford_fulkerson(graph, source=0, sink=5) = }")

sorts/binary_insertion_sort.py

+15-10
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@
1212

1313

1414
def binary_insertion_sort(collection: list) -> list:
15-
"""Pure implementation of the binary insertion sort algorithm in Python
16-
:param collection: some mutable ordered collection with heterogeneous
17-
comparable items inside
18-
:return: the same collection ordered by ascending
15+
"""
16+
Sorts a list using the binary insertion sort algorithm.
17+
18+
:param collection: A mutable ordered collection with comparable items.
19+
:return: The same collection ordered in ascending order.
1920
2021
Examples:
2122
>>> binary_insertion_sort([0, 4, 1234, 4, 1])
@@ -39,23 +40,27 @@ def binary_insertion_sort(collection: list) -> list:
3940

4041
n = len(collection)
4142
for i in range(1, n):
42-
val = collection[i]
43+
value_to_insert = collection[i]
4344
low = 0
4445
high = i - 1
4546

4647
while low <= high:
4748
mid = (low + high) // 2
48-
if val < collection[mid]:
49+
if value_to_insert < collection[mid]:
4950
high = mid - 1
5051
else:
5152
low = mid + 1
5253
for j in range(i, low, -1):
5354
collection[j] = collection[j - 1]
54-
collection[low] = val
55+
collection[low] = value_to_insert
5556
return collection
5657

5758

58-
if __name__ == "__main__":
59+
if __name__ == "__main":
5960
user_input = input("Enter numbers separated by a comma:\n").strip()
60-
unsorted = [int(item) for item in user_input.split(",")]
61-
print(binary_insertion_sort(unsorted))
61+
try:
62+
unsorted = [int(item) for item in user_input.split(",")]
63+
except ValueError:
64+
print("Invalid input. Please enter valid integers separated by commas.")
65+
raise
66+
print(f"{binary_insertion_sort(unsorted) = }")

strings/frequency_finder.py

+9
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@ def get_item_at_index_zero(x: tuple) -> str:
4949

5050

5151
def get_frequency_order(message: str) -> str:
52+
"""
53+
Get the frequency order of the letters in the given string
54+
>>> get_frequency_order('Hello World')
55+
'LOWDRHEZQXJKVBPYGFMUCSNIAT'
56+
>>> get_frequency_order('Hello@')
57+
'LHOEZQXJKVBPYGFWMUCDRSNIAT'
58+
>>> get_frequency_order('h')
59+
'HZQXJKVBPYGFWMUCLDRSNIOATE'
60+
"""
5261
letter_to_freq = get_letter_count(message)
5362
freq_to_letter: dict[int, list[str]] = {
5463
freq: [] for letter, freq in letter_to_freq.items()

web_programming/current_weather.py

+42-22
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,50 @@
11
import requests
22

3-
APPID = "" # <-- Put your OpenWeatherMap appid here!
4-
URL_BASE = "https://api.openweathermap.org/data/2.5/"
5-
6-
7-
def current_weather(q: str = "Chicago", appid: str = APPID) -> dict:
8-
"""https://openweathermap.org/api"""
9-
return requests.get(URL_BASE + "weather", params=locals()).json()
10-
11-
12-
def weather_forecast(q: str = "Kolkata, India", appid: str = APPID) -> dict:
13-
"""https://openweathermap.org/forecast5"""
14-
return requests.get(URL_BASE + "forecast", params=locals()).json()
15-
16-
17-
def weather_onecall(lat: float = 55.68, lon: float = 12.57, appid: str = APPID) -> dict:
18-
"""https://openweathermap.org/api/one-call-api"""
19-
return requests.get(URL_BASE + "onecall", params=locals()).json()
3+
# Put your API key(s) here
4+
OPENWEATHERMAP_API_KEY = ""
5+
WEATHERSTACK_API_KEY = ""
6+
7+
# Define the URL for the APIs with placeholders
8+
OPENWEATHERMAP_URL_BASE = "https://api.openweathermap.org/data/2.5/weather"
9+
WEATHERSTACK_URL_BASE = "http://api.weatherstack.com/current"
10+
11+
12+
def current_weather(location: str) -> list[dict]:
13+
"""
14+
>>> current_weather("location")
15+
Traceback (most recent call last):
16+
...
17+
ValueError: No API keys provided or no valid data returned.
18+
"""
19+
weather_data = []
20+
if OPENWEATHERMAP_API_KEY:
21+
params_openweathermap = {"q": location, "appid": OPENWEATHERMAP_API_KEY}
22+
response_openweathermap = requests.get(
23+
OPENWEATHERMAP_URL_BASE, params=params_openweathermap
24+
)
25+
weather_data.append({"OpenWeatherMap": response_openweathermap.json()})
26+
if WEATHERSTACK_API_KEY:
27+
params_weatherstack = {"query": location, "access_key": WEATHERSTACK_API_KEY}
28+
response_weatherstack = requests.get(
29+
WEATHERSTACK_URL_BASE, params=params_weatherstack
30+
)
31+
weather_data.append({"Weatherstack": response_weatherstack.json()})
32+
if not weather_data:
33+
raise ValueError("No API keys provided or no valid data returned.")
34+
return weather_data
2035

2136

2237
if __name__ == "__main__":
2338
from pprint import pprint
2439

25-
while True:
26-
location = input("Enter a location:").strip()
40+
location = "to be determined..."
41+
while location:
42+
location = input("Enter a location (city name or latitude,longitude): ").strip()
2743
if location:
28-
pprint(current_weather(location))
29-
else:
30-
break
44+
try:
45+
weather_data = current_weather(location)
46+
for forecast in weather_data:
47+
pprint(forecast)
48+
except ValueError as e:
49+
print(repr(e))
50+
location = ""

0 commit comments

Comments
 (0)