Skip to content

Commit 2ba4830

Browse files
authored
Merge branch 'TheAlgorithms:master' into master
2 parents e14e0fb + 7775de0 commit 2ba4830

File tree

3 files changed

+233
-0
lines changed

3 files changed

+233
-0
lines changed

DIRECTORY.md

+1
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,7 @@
729729
* [Maximum Subarray](other/maximum_subarray.py)
730730
* [Maximum Subsequence](other/maximum_subsequence.py)
731731
* [Nested Brackets](other/nested_brackets.py)
732+
* [Number Container System](other/number_container_system.py)
732733
* [Password](other/password.py)
733734
* [Quine](other/quine.py)
734735
* [Scoring Algorithm](other/scoring_algorithm.py)

other/number_container_system.py

+180
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
"""
2+
A number container system that uses binary search to delete and insert values into
3+
arrays with O(n logn) write times and O(1) read times.
4+
5+
This container system holds integers at indexes.
6+
7+
Further explained in this leetcode problem
8+
> https://leetcode.com/problems/minimum-cost-tree-from-leaf-values
9+
"""
10+
11+
12+
class NumberContainer:
13+
def __init__(self) -> None:
14+
# numbermap keys are the number and its values are lists of indexes sorted
15+
# in ascending order
16+
self.numbermap: dict[int, list[int]] = {}
17+
# indexmap keys are an index and it's values are the number at that index
18+
self.indexmap: dict[int, int] = {}
19+
20+
def binary_search_delete(self, array: list | str | range, item: int) -> list[int]:
21+
"""
22+
Removes the item from the sorted array and returns
23+
the new array.
24+
25+
>>> NumberContainer().binary_search_delete([1,2,3], 2)
26+
[1, 3]
27+
>>> NumberContainer().binary_search_delete([0, 0, 0], 0)
28+
[0, 0]
29+
>>> NumberContainer().binary_search_delete([-1, -1, -1], -1)
30+
[-1, -1]
31+
>>> NumberContainer().binary_search_delete([-1, 0], 0)
32+
[-1]
33+
>>> NumberContainer().binary_search_delete([-1, 0], -1)
34+
[0]
35+
>>> NumberContainer().binary_search_delete(range(7), 3)
36+
[0, 1, 2, 4, 5, 6]
37+
>>> NumberContainer().binary_search_delete([1.1, 2.2, 3.3], 2.2)
38+
[1.1, 3.3]
39+
>>> NumberContainer().binary_search_delete("abcde", "c")
40+
['a', 'b', 'd', 'e']
41+
>>> NumberContainer().binary_search_delete([0, -1, 2, 4], 0)
42+
Traceback (most recent call last):
43+
...
44+
ValueError: Either the item is not in the array or the array was unsorted
45+
>>> NumberContainer().binary_search_delete([2, 0, 4, -1, 11], -1)
46+
Traceback (most recent call last):
47+
...
48+
ValueError: Either the item is not in the array or the array was unsorted
49+
>>> NumberContainer().binary_search_delete(125, 1)
50+
Traceback (most recent call last):
51+
...
52+
TypeError: binary_search_delete() only accepts either a list, range or str
53+
"""
54+
if isinstance(array, (range, str)):
55+
array = list(array)
56+
elif not isinstance(array, list):
57+
raise TypeError(
58+
"binary_search_delete() only accepts either a list, range or str"
59+
)
60+
61+
low = 0
62+
high = len(array) - 1
63+
64+
while low <= high:
65+
mid = (low + high) // 2
66+
if array[mid] == item:
67+
array.pop(mid)
68+
return array
69+
elif array[mid] < item:
70+
low = mid + 1
71+
else:
72+
high = mid - 1
73+
raise ValueError(
74+
"Either the item is not in the array or the array was unsorted"
75+
)
76+
77+
def binary_search_insert(self, array: list | str | range, index: int) -> list[int]:
78+
"""
79+
Inserts the index into the sorted array
80+
at the correct position.
81+
82+
>>> NumberContainer().binary_search_insert([1,2,3], 2)
83+
[1, 2, 2, 3]
84+
>>> NumberContainer().binary_search_insert([0,1,3], 2)
85+
[0, 1, 2, 3]
86+
>>> NumberContainer().binary_search_insert([-5, -3, 0, 0, 11, 103], 51)
87+
[-5, -3, 0, 0, 11, 51, 103]
88+
>>> NumberContainer().binary_search_insert([-5, -3, 0, 0, 11, 100, 103], 101)
89+
[-5, -3, 0, 0, 11, 100, 101, 103]
90+
>>> NumberContainer().binary_search_insert(range(10), 4)
91+
[0, 1, 2, 3, 4, 4, 5, 6, 7, 8, 9]
92+
>>> NumberContainer().binary_search_insert("abd", "c")
93+
['a', 'b', 'c', 'd']
94+
>>> NumberContainer().binary_search_insert(131, 23)
95+
Traceback (most recent call last):
96+
...
97+
TypeError: binary_search_insert() only accepts either a list, range or str
98+
"""
99+
if isinstance(array, (range, str)):
100+
array = list(array)
101+
elif not isinstance(array, list):
102+
raise TypeError(
103+
"binary_search_insert() only accepts either a list, range or str"
104+
)
105+
106+
low = 0
107+
high = len(array) - 1
108+
109+
while low <= high:
110+
mid = (low + high) // 2
111+
if array[mid] == index:
112+
# If the item already exists in the array,
113+
# insert it after the existing item
114+
array.insert(mid + 1, index)
115+
return array
116+
elif array[mid] < index:
117+
low = mid + 1
118+
else:
119+
high = mid - 1
120+
121+
# If the item doesn't exist in the array, insert it at the appropriate position
122+
array.insert(low, index)
123+
return array
124+
125+
def change(self, index: int, number: int) -> None:
126+
"""
127+
Changes (sets) the index as number
128+
129+
>>> cont = NumberContainer()
130+
>>> cont.change(0, 10)
131+
>>> cont.change(0, 20)
132+
>>> cont.change(-13, 20)
133+
>>> cont.change(-100030, 20032903290)
134+
"""
135+
# Remove previous index
136+
if index in self.indexmap:
137+
n = self.indexmap[index]
138+
if len(self.numbermap[n]) == 1:
139+
del self.numbermap[n]
140+
else:
141+
self.numbermap[n] = self.binary_search_delete(self.numbermap[n], index)
142+
143+
# Set new index
144+
self.indexmap[index] = number
145+
146+
# Number not seen before or empty so insert number value
147+
if number not in self.numbermap:
148+
self.numbermap[number] = [index]
149+
150+
# Here we need to perform a binary search insertion in order to insert
151+
# The item in the correct place
152+
else:
153+
self.numbermap[number] = self.binary_search_insert(
154+
self.numbermap[number], index
155+
)
156+
157+
def find(self, number: int) -> int:
158+
"""
159+
Returns the smallest index where the number is.
160+
161+
>>> cont = NumberContainer()
162+
>>> cont.find(10)
163+
-1
164+
>>> cont.change(0, 10)
165+
>>> cont.find(10)
166+
0
167+
>>> cont.change(0, 20)
168+
>>> cont.find(10)
169+
-1
170+
>>> cont.find(20)
171+
0
172+
"""
173+
# Simply return the 0th index (smallest) of the indexes found (or -1)
174+
return self.numbermap.get(number, [-1])[0]
175+
176+
177+
if __name__ == "__main__":
178+
import doctest
179+
180+
doctest.testmod()

physics/speed_of_sound.py

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
"""
2+
Title : Calculating the speed of sound
3+
4+
Description :
5+
The speed of sound (c) is the speed that a sound wave travels
6+
per unit time (m/s). During propagation, the sound wave propagates
7+
through an elastic medium. Its SI unit is meter per second (m/s).
8+
9+
Only longitudinal waves can propagate in liquids and gas other then
10+
solid where they also travel in transverse wave. The following Algo-
11+
rithem calculates the speed of sound in fluid depanding on the bulk
12+
module and the density of the fluid.
13+
14+
Equation for calculating speed od sound in fluid:
15+
c_fluid = (K_s*p)**0.5
16+
17+
c_fluid: speed of sound in fluid
18+
K_s: isentropic bulk modulus
19+
p: density of fluid
20+
21+
22+
23+
Source : https://en.wikipedia.org/wiki/Speed_of_sound
24+
"""
25+
26+
27+
def speed_of_sound_in_a_fluid(density: float, bulk_modulus: float) -> float:
28+
"""
29+
This method calculates the speed of sound in fluid -
30+
This is calculated from the other two provided values
31+
Examples:
32+
Example 1 --> Water 20°C: bulk_moduls= 2.15MPa, density=998kg/m³
33+
Example 2 --> Murcery 20°: bulk_moduls= 28.5MPa, density=13600kg/m³
34+
35+
>>> speed_of_sound_in_a_fluid(bulk_modulus=2.15*10**9, density=998)
36+
1467.7563207952705
37+
>>> speed_of_sound_in_a_fluid(bulk_modulus=28.5*10**9, density=13600)
38+
1447.614670861731
39+
"""
40+
41+
if density <= 0:
42+
raise ValueError("Impossible fluid density")
43+
if bulk_modulus <= 0:
44+
raise ValueError("Impossible bulk modulus")
45+
46+
return (bulk_modulus / density) ** 0.5
47+
48+
49+
if __name__ == "__main__":
50+
import doctest
51+
52+
doctest.testmod()

0 commit comments

Comments
 (0)