Skip to content

Commit 171ba25

Browse files
authored
Merge pull request TheAlgorithms#2 from TheAlgorithms/master
update
2 parents df2fc9e + 8107548 commit 171ba25

File tree

11 files changed

+436
-27
lines changed

11 files changed

+436
-27
lines changed

Diff for: .github/workflows/autoblack.yml

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# GitHub Action that uses Black to reformat the Python code in an incoming pull request.
2+
# If all Python code in the pull request is complient with Black then this Action does nothing.
3+
# Othewrwise, Black is run and its changes are committed back to the incoming pull request.
4+
# https://github.com/cclauss/autoblack
5+
6+
name: autoblack
7+
on: [pull_request]
8+
jobs:
9+
build:
10+
runs-on: ubuntu-latest
11+
strategy:
12+
max-parallel: 1
13+
matrix:
14+
python-version: [3.7]
15+
steps:
16+
- uses: actions/checkout@v1
17+
- name: Set up Python ${{ matrix.python-version }}
18+
uses: actions/setup-python@v1
19+
with:
20+
python-version: ${{ matrix.python-version }}
21+
- name: Install psf/black
22+
run: pip install black
23+
- name: Run black --check .
24+
run: black --check .
25+
- name: If needed, commit black changes to the pull request
26+
if: failure()
27+
run: |
28+
black .
29+
git config --global user.name 'autoblack'
30+
git config --global user.email '[email protected]'
31+
git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY
32+
git checkout $GITHUB_HEAD_REF
33+
git commit -am "fixup: Format Python code with psf/black"
34+
git push

Diff for: .travis.yml

+1-2
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,4 @@ script:
1111
- mypy --ignore-missing-imports .
1212
- pytest . --doctest-modules
1313
after_success:
14-
- scripts/build_directory_md.py > DIRECTORY.md
15-
- cat DIRECTORY.md
14+
- scripts/build_directory_md.py 2>&1 | tee DIRECTORY.md
+153
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
"""
2+
A non-recursive Segment Tree implementation with range query and single element update,
3+
works virtually with any list of the same type of elements with a "commutative" combiner.
4+
5+
Explanation:
6+
https://www.geeksforgeeks.org/iterative-segment-tree-range-minimum-query/
7+
https://www.geeksforgeeks.org/segment-tree-efficient-implementation/
8+
9+
>>> SegmentTree([1, 2, 3], lambda a, b: a + b).query(0, 2)
10+
6
11+
>>> SegmentTree([3, 1, 2], min).query(0, 2)
12+
1
13+
>>> SegmentTree([2, 3, 1], max).query(0, 2)
14+
3
15+
>>> st = SegmentTree([1, 5, 7, -1, 6], lambda a, b: a + b)
16+
>>> st.update(1, -1)
17+
>>> st.update(2, 3)
18+
>>> st.query(1, 2)
19+
2
20+
>>> st.query(1, 1)
21+
-1
22+
>>> st.update(4, 1)
23+
>>> st.query(3, 4)
24+
0
25+
>>> st = SegmentTree([[1, 2, 3], [3, 2, 1], [1, 1, 1]], lambda a, b: [a[i] + b[i] for i in range(len(a))])
26+
>>> st.query(0, 1)
27+
[4, 4, 4]
28+
>>> st.query(1, 2)
29+
[4, 3, 2]
30+
>>> st.update(1, [-1, -1, -1])
31+
>>> st.query(1, 2)
32+
[0, 0, 0]
33+
>>> st.query(0, 2)
34+
[1, 2, 3]
35+
"""
36+
from typing import List, Callable, TypeVar
37+
38+
T = TypeVar("T")
39+
40+
41+
class SegmentTree:
42+
def __init__(self, arr: List[T], fnc: Callable[[T, T], T]) -> None:
43+
"""
44+
Segment Tree constructor, it works just with commutative combiner.
45+
:param arr: list of elements for the segment tree
46+
:param fnc: commutative function for combine two elements
47+
48+
>>> SegmentTree(['a', 'b', 'c'], lambda a, b: '{}{}'.format(a, b)).query(0, 2)
49+
'abc'
50+
>>> SegmentTree([(1, 2), (2, 3), (3, 4)], lambda a, b: (a[0] + b[0], a[1] + b[1])).query(0, 2)
51+
(6, 9)
52+
"""
53+
self.N = len(arr)
54+
self.st = [None for _ in range(len(arr))] + arr
55+
self.fn = fnc
56+
self.build()
57+
58+
def build(self) -> None:
59+
for p in range(self.N - 1, 0, -1):
60+
self.st[p] = self.fn(self.st[p * 2], self.st[p * 2 + 1])
61+
62+
def update(self, p: int, v: T) -> None:
63+
"""
64+
Update an element in log(N) time
65+
:param p: position to be update
66+
:param v: new value
67+
68+
>>> st = SegmentTree([3, 1, 2, 4], min)
69+
>>> st.query(0, 3)
70+
1
71+
>>> st.update(2, -1)
72+
>>> st.query(0, 3)
73+
-1
74+
"""
75+
p += self.N
76+
self.st[p] = v
77+
while p > 1:
78+
p = p // 2
79+
self.st[p] = self.fn(self.st[p * 2], self.st[p * 2 + 1])
80+
81+
def query(self, l: int, r: int) -> T:
82+
"""
83+
Get range query value in log(N) time
84+
:param l: left element index
85+
:param r: right element index
86+
:return: element combined in the range [l, r]
87+
88+
>>> st = SegmentTree([1, 2, 3, 4], lambda a, b: a + b)
89+
>>> st.query(0, 2)
90+
6
91+
>>> st.query(1, 2)
92+
5
93+
>>> st.query(0, 3)
94+
10
95+
>>> st.query(2, 3)
96+
7
97+
"""
98+
l, r = l + self.N, r + self.N
99+
res = None
100+
while l <= r:
101+
if l % 2 == 1:
102+
res = self.st[l] if res is None else self.fn(res, self.st[l])
103+
if r % 2 == 0:
104+
res = self.st[r] if res is None else self.fn(res, self.st[r])
105+
l, r = (l + 1) // 2, (r - 1) // 2
106+
return res
107+
108+
109+
if __name__ == "__main__":
110+
from functools import reduce
111+
112+
test_array = [1, 10, -2, 9, -3, 8, 4, -7, 5, 6, 11, -12]
113+
114+
test_updates = {
115+
0: 7,
116+
1: 2,
117+
2: 6,
118+
3: -14,
119+
4: 5,
120+
5: 4,
121+
6: 7,
122+
7: -10,
123+
8: 9,
124+
9: 10,
125+
10: 12,
126+
11: 1,
127+
}
128+
129+
min_segment_tree = SegmentTree(test_array, min)
130+
max_segment_tree = SegmentTree(test_array, max)
131+
sum_segment_tree = SegmentTree(test_array, lambda a, b: a + b)
132+
133+
def test_all_segments():
134+
"""
135+
Test all possible segments
136+
"""
137+
for i in range(len(test_array)):
138+
for j in range(i, len(test_array)):
139+
min_range = reduce(min, test_array[i : j + 1])
140+
max_range = reduce(max, test_array[i : j + 1])
141+
sum_range = reduce(lambda a, b: a + b, test_array[i : j + 1])
142+
assert min_range == min_segment_tree.query(i, j)
143+
assert max_range == max_segment_tree.query(i, j)
144+
assert sum_range == sum_segment_tree.query(i, j)
145+
146+
test_all_segments()
147+
148+
for index, value in test_updates.items():
149+
test_array[index] = value
150+
min_segment_tree.update(index, value)
151+
max_segment_tree.update(index, value)
152+
sum_segment_tree.update(index, value)
153+
test_all_segments()

Diff for: dynamic_programming/max_sum_contigous_subsequence.py

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
def max_subarray_sum(nums: list) -> int:
2+
"""
3+
>>> max_subarray_sum([6 , 9, -1, 3, -7, -5, 10])
4+
17
5+
"""
6+
if not nums:
7+
return 0
8+
n = len(nums)
9+
s = [0] * n
10+
res, s, s_pre = nums[0], nums[0], nums[0]
11+
for i in range(1, n):
12+
s = max(nums[i], s_pre + nums[i])
13+
s_pre = s
14+
res = max(res, s)
15+
return res
16+
17+
18+
if __name__ == "__main__":
19+
nums = [6, 9, -1, 3, -7, -5, 10]
20+
print(max_subarray_sum(nums))

Diff for: maths/factorial_python.py

+28-15
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,34 @@
11
def factorial(input_number: int) -> int:
22
"""
3-
Non-recursive algorithm of finding factorial of the
4-
input number.
5-
>>> factorial(1)
6-
1
7-
>>> factorial(6)
8-
720
9-
>>> factorial(0)
10-
1
3+
Calculate the factorial of specified number
4+
5+
>>> factorial(1)
6+
1
7+
>>> factorial(6)
8+
720
9+
>>> factorial(0)
10+
1
11+
>>> factorial(-1)
12+
Traceback (most recent call last):
13+
...
14+
ValueError: factorial() not defined for negative values
15+
>>> factorial(0.1)
16+
Traceback (most recent call last):
17+
...
18+
ValueError: factorial() only accepts integral values
1119
"""
1220

1321
if input_number < 0:
14-
raise ValueError("Input input_number should be non-negative")
15-
elif input_number == 0:
16-
return 1
17-
else:
18-
result = 1
19-
for i in range(input_number):
20-
result = result * (i + 1)
22+
raise ValueError("factorial() not defined for negative values")
23+
if not isinstance(input_number, int):
24+
raise ValueError("factorial() only accepts integral values")
25+
result = 1
26+
for i in range(1, input_number):
27+
result = result * (i + 1)
2128
return result
29+
30+
31+
if __name__ == '__main__':
32+
import doctest
33+
34+
doctest.testmod()

Diff for: maths/factorial_recursive.py

+26-10
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,30 @@
1-
def fact(n):
1+
def factorial(n: int) -> int:
22
"""
3-
Return 1, if n is 1 or below,
4-
otherwise, return n * fact(n-1).
3+
Calculate the factorial of specified number
4+
5+
>>> factorial(1)
6+
1
7+
>>> factorial(6)
8+
720
9+
>>> factorial(0)
10+
1
11+
>>> factorial(-1)
12+
Traceback (most recent call last):
13+
...
14+
ValueError: factorial() not defined for negative values
15+
>>> factorial(0.1)
16+
Traceback (most recent call last):
17+
...
18+
ValueError: factorial() only accepts integral values
519
"""
6-
return 1 if n <= 1 else n * fact(n - 1)
20+
if n < 0:
21+
raise ValueError("factorial() not defined for negative values")
22+
if not isinstance(n, int):
23+
raise ValueError("factorial() only accepts integral values")
24+
return 1 if n == 0 or n == 1 else n * factorial(n - 1)
25+
726

27+
if __name__ == '__main__':
28+
import doctest
829

9-
"""
10-
Show factorial for i,
11-
where i ranges from 1 to 20.
12-
"""
13-
for i in range(1, 21):
14-
print(i, ": ", fact(i), sep="")
30+
doctest.testmod()

Diff for: maths/perfect_square.py

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import math
2+
3+
4+
def perfect_square(num: int) -> bool:
5+
"""
6+
Check if a number is perfect square number or not
7+
:param num: the number to be checked
8+
:return: True if number is square number, otherwise False
9+
10+
>>> perfect_square(9)
11+
True
12+
>>> perfect_square(16)
13+
True
14+
>>> perfect_square(1)
15+
True
16+
>>> perfect_square(0)
17+
True
18+
>>> perfect_square(10)
19+
False
20+
"""
21+
return math.sqrt(num) * math.sqrt(num) == num
22+
23+
24+
if __name__ == '__main__':
25+
import doctest
26+
27+
doctest.testmod()

0 commit comments

Comments
 (0)