mirror of
https://github.com/TheAlgorithms/Python.git
synced 2025-02-20 00:02:04 +00:00
Compare commits
11 Commits
a36b2acb28
...
ac5f2accc0
Author | SHA1 | Date | |
---|---|---|---|
|
ac5f2accc0 | ||
|
6c92c5a539 | ||
|
13e4d3e76c | ||
|
c666db3729 | ||
|
9fb51b4169 | ||
|
1f74db0c06 | ||
|
91ebea1d99 | ||
|
533767ff46 | ||
|
0040ad47f9 | ||
|
f04d308431 | ||
|
72eebdeba7 |
2
.github/workflows/sphinx.yml
vendored
2
.github/workflows/sphinx.yml
vendored
|
@ -23,7 +23,7 @@ concurrency:
|
|||
|
||||
jobs:
|
||||
build_docs:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-24.04-arm
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: astral-sh/setup-uv@v5
|
||||
|
|
|
@ -16,13 +16,13 @@ repos:
|
|||
- id: auto-walrus
|
||||
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.9.1
|
||||
rev: v0.9.3
|
||||
hooks:
|
||||
- id: ruff
|
||||
- id: ruff-format
|
||||
|
||||
- repo: https://github.com/codespell-project/codespell
|
||||
rev: v2.3.0
|
||||
rev: v2.4.0
|
||||
hooks:
|
||||
- id: codespell
|
||||
additional_dependencies:
|
||||
|
|
|
@ -377,6 +377,7 @@
|
|||
* [Longest Common Subsequence](dynamic_programming/longest_common_subsequence.py)
|
||||
* [Longest Common Substring](dynamic_programming/longest_common_substring.py)
|
||||
* [Longest Increasing Subsequence](dynamic_programming/longest_increasing_subsequence.py)
|
||||
* [Longest Increasing Subsequence Iterative](dynamic_programming/longest_increasing_subsequence_iterative.py)
|
||||
* [Longest Increasing Subsequence O Nlogn](dynamic_programming/longest_increasing_subsequence_o_nlogn.py)
|
||||
* [Longest Palindromic Subsequence](dynamic_programming/longest_palindromic_subsequence.py)
|
||||
* [Matrix Chain Multiplication](dynamic_programming/matrix_chain_multiplication.py)
|
||||
|
@ -462,6 +463,7 @@
|
|||
|
||||
## Graphics
|
||||
* [Bezier Curve](graphics/bezier_curve.py)
|
||||
* [Butterfly Pattern](graphics/butterfly_pattern.py)
|
||||
* [Digital Differential Analyzer Line](graphics/digital_differential_analyzer_line.py)
|
||||
* [Vector3 For 2D Rendering](graphics/vector3_for_2d_rendering.py)
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ def __prepare(
|
|||
...
|
||||
KeyError: 'Length of alphabet has to be 27.'
|
||||
|
||||
Testing with punctuations that are not in the given alphabet
|
||||
Testing with punctuation not in the given alphabet
|
||||
|
||||
>>> __prepare('am i a boy?','abCdeFghijkLmnopqrStuVwxYZ+')
|
||||
Traceback (most recent call last):
|
||||
|
@ -128,7 +128,7 @@ def encrypt_message(
|
|||
encrypt_message
|
||||
===============
|
||||
|
||||
Encrypts a message using the trifid_cipher. Any punctuatuions that
|
||||
Encrypts a message using the trifid_cipher. Any punctuatuion chars that
|
||||
would be used should be added to the alphabet.
|
||||
|
||||
PARAMETERS
|
||||
|
|
|
@ -9,7 +9,9 @@ import time
|
|||
|
||||
|
||||
def cross(items_a, items_b):
|
||||
"Cross product of elements in A and elements in B."
|
||||
"""
|
||||
Cross product of elements in A and elements in B.
|
||||
"""
|
||||
return [a + b for a in items_a for b in items_b]
|
||||
|
||||
|
||||
|
@ -27,7 +29,7 @@ peers = {s: {x for u in units[s] for x in u} - {s} for s in squares}
|
|||
|
||||
|
||||
def test():
|
||||
"A set of unit tests."
|
||||
"""A set of unit tests."""
|
||||
assert len(squares) == 81
|
||||
assert len(unitlist) == 27
|
||||
assert all(len(units[s]) == 3 for s in squares)
|
||||
|
@ -47,8 +49,10 @@ def test():
|
|||
|
||||
|
||||
def parse_grid(grid):
|
||||
"""Convert grid to a dict of possible values, {square: digits}, or
|
||||
return False if a contradiction is detected."""
|
||||
"""
|
||||
Convert grid to a dict of possible values, {square: digits}, or
|
||||
return False if a contradiction is detected.
|
||||
"""
|
||||
## To start, every square can be any digit; then assign values from the grid.
|
||||
values = {s: digits for s in squares}
|
||||
for s, d in grid_values(grid).items():
|
||||
|
@ -58,15 +62,19 @@ def parse_grid(grid):
|
|||
|
||||
|
||||
def grid_values(grid):
|
||||
"Convert grid into a dict of {square: char} with '0' or '.' for empties."
|
||||
"""
|
||||
Convert grid into a dict of {square: char} with '0' or '.' for empties.
|
||||
"""
|
||||
chars = [c for c in grid if c in digits or c in "0."]
|
||||
assert len(chars) == 81
|
||||
return dict(zip(squares, chars))
|
||||
|
||||
|
||||
def assign(values, s, d):
|
||||
"""Eliminate all the other values (except d) from values[s] and propagate.
|
||||
Return values, except return False if a contradiction is detected."""
|
||||
"""
|
||||
Eliminate all the other values (except d) from values[s] and propagate.
|
||||
Return values, except return False if a contradiction is detected.
|
||||
"""
|
||||
other_values = values[s].replace(d, "")
|
||||
if all(eliminate(values, s, d2) for d2 in other_values):
|
||||
return values
|
||||
|
@ -75,8 +83,10 @@ def assign(values, s, d):
|
|||
|
||||
|
||||
def eliminate(values, s, d):
|
||||
"""Eliminate d from values[s]; propagate when values or places <= 2.
|
||||
Return values, except return False if a contradiction is detected."""
|
||||
"""
|
||||
Eliminate d from values[s]; propagate when values or places <= 2.
|
||||
Return values, except return False if a contradiction is detected.
|
||||
"""
|
||||
if d not in values[s]:
|
||||
return values ## Already eliminated
|
||||
values[s] = values[s].replace(d, "")
|
||||
|
@ -99,7 +109,9 @@ def eliminate(values, s, d):
|
|||
|
||||
|
||||
def display(values):
|
||||
"Display these values as a 2-D grid."
|
||||
"""
|
||||
Display these values as a 2-D grid.
|
||||
"""
|
||||
width = 1 + max(len(values[s]) for s in squares)
|
||||
line = "+".join(["-" * (width * 3)] * 3)
|
||||
for r in rows:
|
||||
|
@ -114,11 +126,14 @@ def display(values):
|
|||
|
||||
|
||||
def solve(grid):
|
||||
"""
|
||||
Solve the grid.
|
||||
"""
|
||||
return search(parse_grid(grid))
|
||||
|
||||
|
||||
def some(seq):
|
||||
"Return some element of seq that is true."
|
||||
"""Return some element of seq that is true."""
|
||||
for e in seq:
|
||||
if e:
|
||||
return e
|
||||
|
@ -126,7 +141,9 @@ def some(seq):
|
|||
|
||||
|
||||
def search(values):
|
||||
"Using depth-first search and propagation, try all possible values."
|
||||
"""
|
||||
Using depth-first search and propagation, try all possible values.
|
||||
"""
|
||||
if values is False:
|
||||
return False ## Failed earlier
|
||||
if all(len(values[s]) == 1 for s in squares):
|
||||
|
@ -137,9 +154,11 @@ def search(values):
|
|||
|
||||
|
||||
def solve_all(grids, name="", showif=0.0):
|
||||
"""Attempt to solve a sequence of grids. Report results.
|
||||
"""
|
||||
Attempt to solve a sequence of grids. Report results.
|
||||
When showif is a number of seconds, display puzzles that take longer.
|
||||
When showif is None, don't display any puzzles."""
|
||||
When showif is None, don't display any puzzles.
|
||||
"""
|
||||
|
||||
def time_solve(grid):
|
||||
start = time.monotonic()
|
||||
|
@ -162,7 +181,9 @@ def solve_all(grids, name="", showif=0.0):
|
|||
|
||||
|
||||
def solved(values):
|
||||
"A puzzle is solved if each unit is a permutation of the digits 1 to 9."
|
||||
"""
|
||||
A puzzle is solved if each unit is a permutation of the digits 1 to 9.
|
||||
"""
|
||||
|
||||
def unitsolved(unit):
|
||||
return {values[s] for s in unit} == set(digits)
|
||||
|
@ -177,9 +198,11 @@ def from_file(filename, sep="\n"):
|
|||
|
||||
|
||||
def random_puzzle(assignments=17):
|
||||
"""Make a random puzzle with N or more assignments. Restart on contradictions.
|
||||
"""
|
||||
Make a random puzzle with N or more assignments. Restart on contradictions.
|
||||
Note the resulting puzzle is not guaranteed to be solvable, but empirically
|
||||
about 99.8% of them are solvable. Some have multiple solutions."""
|
||||
about 99.8% of them are solvable. Some have multiple solutions.
|
||||
"""
|
||||
values = {s: digits for s in squares}
|
||||
for s in shuffled(squares):
|
||||
if not assign(values, s, random.choice(values[s])):
|
||||
|
@ -191,7 +214,9 @@ def random_puzzle(assignments=17):
|
|||
|
||||
|
||||
def shuffled(seq):
|
||||
"Return a randomly shuffled copy of the input sequence."
|
||||
"""
|
||||
Return a randomly shuffled copy of the input sequence.
|
||||
"""
|
||||
seq = list(seq)
|
||||
random.shuffle(seq)
|
||||
return seq
|
||||
|
|
|
@ -221,6 +221,10 @@ def del_node(root: MyNode, data: Any) -> MyNode | None:
|
|||
else:
|
||||
root.set_right(del_node(right_child, data))
|
||||
|
||||
# Re-fetch left_child and right_child references
|
||||
left_child = root.get_left()
|
||||
right_child = root.get_right()
|
||||
|
||||
if get_height(right_child) - get_height(left_child) == 2:
|
||||
assert right_child is not None
|
||||
if get_height(right_child.get_right()) > get_height(right_child.get_left()):
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
"""
|
||||
Author : Sanjay Muthu <https://github.com/XenoBytesX>
|
||||
|
||||
This is a pure Python implementation of Dynamic Programming solution to the longest
|
||||
increasing subsequence of a given sequence.
|
||||
|
||||
The problem is:
|
||||
Given an array, to find the longest and increasing sub-array in that given array and
|
||||
return it.
|
||||
|
||||
Example:
|
||||
``[10, 22, 9, 33, 21, 50, 41, 60, 80]`` as input will return
|
||||
``[10, 22, 33, 50, 60, 80]`` as output
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
|
||||
|
||||
def longest_subsequence(array: list[int]) -> list[int]:
|
||||
"""
|
||||
Some examples
|
||||
|
||||
>>> longest_subsequence([10, 22, 9, 33, 21, 50, 41, 60, 80])
|
||||
[10, 22, 33, 50, 60, 80]
|
||||
>>> longest_subsequence([4, 8, 7, 5, 1, 12, 2, 3, 9])
|
||||
[1, 2, 3, 9]
|
||||
>>> longest_subsequence([9, 8, 7, 6, 5, 7])
|
||||
[7, 7]
|
||||
>>> longest_subsequence([28, 26, 12, 23, 35, 39])
|
||||
[12, 23, 35, 39]
|
||||
>>> longest_subsequence([1, 1, 1])
|
||||
[1, 1, 1]
|
||||
>>> longest_subsequence([])
|
||||
[]
|
||||
"""
|
||||
n = len(array)
|
||||
# The longest increasing subsequence ending at array[i]
|
||||
longest_increasing_subsequence = []
|
||||
for i in range(n):
|
||||
longest_increasing_subsequence.append([array[i]])
|
||||
|
||||
for i in range(1, n):
|
||||
for prev in range(i):
|
||||
# If array[prev] is less than or equal to array[i], then
|
||||
# longest_increasing_subsequence[prev] + array[i]
|
||||
# is a valid increasing subsequence
|
||||
|
||||
# longest_increasing_subsequence[i] is only set to
|
||||
# longest_increasing_subsequence[prev] + array[i] if the length is longer.
|
||||
|
||||
if array[prev] <= array[i] and len(
|
||||
longest_increasing_subsequence[prev]
|
||||
) + 1 > len(longest_increasing_subsequence[i]):
|
||||
longest_increasing_subsequence[i] = copy.copy(
|
||||
longest_increasing_subsequence[prev]
|
||||
)
|
||||
longest_increasing_subsequence[i].append(array[i])
|
||||
|
||||
result: list[int] = []
|
||||
for i in range(n):
|
||||
if len(longest_increasing_subsequence[i]) > len(result):
|
||||
result = longest_increasing_subsequence[i]
|
||||
|
||||
return result
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
|
||||
doctest.testmod()
|
58
financial/get_ordinary_annuity_future_value.py
Normal file
58
financial/get_ordinary_annuity_future_value.py
Normal file
|
@ -0,0 +1,58 @@
|
|||
"""
|
||||
An ordinary annuity means making or requiring payments at the end
|
||||
of each term during a given period.
|
||||
For example, if the given period is 3 terms long and the payment
|
||||
for each term is $1000, then the cash flow is as follows:
|
||||
|
||||
0: no payment --- 1: $1000 --- 2: $1000 --- 3: $1000
|
||||
|
||||
The function, get_ordinary_annuity_future_value, calculates the future value of
|
||||
the given ordinary annuity. In the example above, the function should return
|
||||
the sum of each payment's future value at the end of term 3,
|
||||
which means the sum is returned as soon as the last payment is made.
|
||||
|
||||
More info on: https://www.investopedia.com/retirement/calculating-present-and-future-value-of-annuities
|
||||
|
||||
This function can help to understand how much you will receive
|
||||
if you make a regular deposit at the end of each term
|
||||
for saving with a fix period and interest rate.
|
||||
"""
|
||||
|
||||
|
||||
def get_ordinary_annuity_future_value(
|
||||
term_payment: float, number_of_payments: int, term_interest_rate: float
|
||||
) -> float:
|
||||
"""
|
||||
Calculate the future value of the given ordinary annuity
|
||||
:param term_payment: payment made at the end of each term
|
||||
:param number_of_payments: the number of payments
|
||||
:param term_interest_rate: the interest rate for each term
|
||||
:return: the future value (maturity value) of the given ordinary annuity
|
||||
|
||||
Examples:
|
||||
>>> round(get_ordinary_annuity_future_value(500, 10, 0.05), 2)
|
||||
6288.95
|
||||
>>> round(get_ordinary_annuity_future_value(1000, 10, 0.05), 2)
|
||||
12577.89
|
||||
>>> round(get_ordinary_annuity_future_value(1000, 10, 0.10), 2)
|
||||
15937.42
|
||||
>>> round(get_ordinary_annuity_future_value(1000, 20, 0.10), 2)
|
||||
57275.0
|
||||
"""
|
||||
|
||||
annuity_factor = (
|
||||
((1 + term_interest_rate) ** number_of_payments) - 1
|
||||
) / term_interest_rate
|
||||
future_value = term_payment * annuity_factor
|
||||
return future_value
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
user_input_amount = float(input("How much money will be deposited each term?\n> "))
|
||||
user_input_payment_number = int(input("How many payments will be made?\n> "))
|
||||
term_interest_rate = float(input("What is the interest rate per term?\n> "))
|
||||
print(
|
||||
get_ordinary_annuity_future_value(
|
||||
user_input_amount, user_input_payment_number, term_interest_rate
|
||||
)
|
||||
)
|
46
graphics/butterfly_pattern.py
Normal file
46
graphics/butterfly_pattern.py
Normal file
|
@ -0,0 +1,46 @@
|
|||
def butterfly_pattern(n: int) -> str:
|
||||
"""
|
||||
Creates a butterfly pattern of size n and returns it as a string.
|
||||
|
||||
>>> print(butterfly_pattern(3))
|
||||
* *
|
||||
** **
|
||||
*****
|
||||
** **
|
||||
* *
|
||||
>>> print(butterfly_pattern(5))
|
||||
* *
|
||||
** **
|
||||
*** ***
|
||||
**** ****
|
||||
*********
|
||||
**** ****
|
||||
*** ***
|
||||
** **
|
||||
* *
|
||||
"""
|
||||
result = []
|
||||
|
||||
# Upper part
|
||||
for i in range(1, n):
|
||||
left_stars = "*" * i
|
||||
spaces = " " * (2 * (n - i) - 1)
|
||||
right_stars = "*" * i
|
||||
result.append(left_stars + spaces + right_stars)
|
||||
|
||||
# Middle part
|
||||
result.append("*" * (2 * n - 1))
|
||||
|
||||
# Lower part
|
||||
for i in range(n - 1, 0, -1):
|
||||
left_stars = "*" * i
|
||||
spaces = " " * (2 * (n - i) - 1)
|
||||
right_stars = "*" * i
|
||||
result.append(left_stars + spaces + right_stars)
|
||||
|
||||
return "\n".join(result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
n = int(input("Enter the size of the butterfly pattern: "))
|
||||
print(butterfly_pattern(n))
|
|
@ -46,7 +46,7 @@ def get_week_day(year: int, month: int, day: int) -> str:
|
|||
) % 7
|
||||
day_anchor = (
|
||||
DOOMSDAY_NOT_LEAP[month - 1]
|
||||
if (year % 4 != 0) or (centurian == 0 and (year % 400) == 0)
|
||||
if year % 4 != 0 or (centurian == 0 and year % 400 != 0)
|
||||
else DOOMSDAY_LEAP[month - 1]
|
||||
)
|
||||
week_day = (dooms_day + day - day_anchor) % 7
|
||||
|
|
|
@ -159,7 +159,7 @@ lint.pylint.max-returns = 8 # default: 6
|
|||
lint.pylint.max-statements = 88 # default: 50
|
||||
|
||||
[tool.codespell]
|
||||
ignore-words-list = "3rt,ans,bitap,crate,damon,fo,followings,hist,iff,kwanza,manuel,mater,secant,som,sur,tim,toi,zar"
|
||||
ignore-words-list = "3rt,abd,aer,ans,bitap,crate,damon,fo,followings,hist,iff,kwanza,manuel,mater,secant,som,sur,tim,toi,zar"
|
||||
skip = "./.*,*.json,*.lock,ciphers/prehistoric_men.txt,project_euler/problem_022/p022_names.txt,pyproject.toml,strings/dictionary.txt,strings/words.txt"
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
|
|
|
@ -85,6 +85,8 @@ def bubble_sort_recursive(collection: list[Any]) -> list[Any]:
|
|||
[1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7]
|
||||
>>> bubble_sort_recursive([1, 3.3, 5, 7.7, 2, 4.4, 6])
|
||||
[1, 2, 3.3, 4.4, 5, 6, 7.7]
|
||||
>>> bubble_sort_recursive(['a', 'Z', 'B', 'C', 'A', 'c'])
|
||||
['A', 'B', 'C', 'Z', 'a', 'c']
|
||||
>>> import random
|
||||
>>> collection_arg = random.sample(range(-50, 50), 100)
|
||||
>>> bubble_sort_recursive(collection_arg) == sorted(collection_arg)
|
||||
|
|
Loading…
Reference in New Issue
Block a user