Merge and add benchmarks to palindrome algorithms in the strings/ directory (#8749)

* refactor: Merge and add benchmarks to palindrome

* updating DIRECTORY.md

* chore: Fix failing tests

* Update strings/palindrome.py

Co-authored-by: Christian Clauss <cclauss@me.com>

* Update palindrome.py

---------

Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
Co-authored-by: Christian Clauss <cclauss@me.com>
This commit is contained in:
Caeden Perelli-Harris 2023-05-25 11:56:23 +01:00 committed by GitHub
parent a6631487b0
commit cfbbfd9896
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 39 additions and 43 deletions

View File

@ -1156,7 +1156,6 @@
* [Indian Phone Validator](strings/indian_phone_validator.py) * [Indian Phone Validator](strings/indian_phone_validator.py)
* [Is Contains Unique Chars](strings/is_contains_unique_chars.py) * [Is Contains Unique Chars](strings/is_contains_unique_chars.py)
* [Is Isogram](strings/is_isogram.py) * [Is Isogram](strings/is_isogram.py)
* [Is Palindrome](strings/is_palindrome.py)
* [Is Pangram](strings/is_pangram.py) * [Is Pangram](strings/is_pangram.py)
* [Is Spain National Id](strings/is_spain_national_id.py) * [Is Spain National Id](strings/is_spain_national_id.py)
* [Is Srilankan Phone Number](strings/is_srilankan_phone_number.py) * [Is Srilankan Phone Number](strings/is_srilankan_phone_number.py)

View File

@ -1,41 +0,0 @@
def is_palindrome(s: str) -> bool:
"""
Determine if the string s is a palindrome.
>>> is_palindrome("A man, A plan, A canal -- Panama!")
True
>>> is_palindrome("Hello")
False
>>> is_palindrome("Able was I ere I saw Elba")
True
>>> is_palindrome("racecar")
True
>>> is_palindrome("Mr. Owl ate my metal worm?")
True
"""
# Since punctuation, capitalization, and spaces are often ignored while checking
# palindromes, we first remove them from our string.
s = "".join(character for character in s.lower() if character.isalnum())
# return s == s[::-1] the slicing method
# uses extra spaces we can
# better with iteration method.
end = len(s) // 2
n = len(s)
# We need to traverse till half of the length of string
# as we can get access of the i'th last element from
# i'th index.
# eg: [0,1,2,3,4,5] => 4th index can be accessed
# with the help of 1st index (i==n-i-1)
# where n is length of string
return all(s[i] == s[n - i - 1] for i in range(end))
if __name__ == "__main__":
s = input("Please enter a string to see if it is a palindrome: ")
if is_palindrome(s):
print(f"'{s}' is a palindrome.")
else:
print(f"'{s}' is not a palindrome.")

View File

@ -1,5 +1,7 @@
# Algorithms to determine if a string is palindrome # Algorithms to determine if a string is palindrome
from timeit import timeit
test_data = { test_data = {
"MALAYALAM": True, "MALAYALAM": True,
"String": False, "String": False,
@ -33,6 +35,25 @@ def is_palindrome(s: str) -> bool:
return True return True
def is_palindrome_traversal(s: str) -> bool:
"""
Return True if s is a palindrome otherwise return False.
>>> all(is_palindrome_traversal(key) is value for key, value in test_data.items())
True
"""
end = len(s) // 2
n = len(s)
# We need to traverse till half of the length of string
# as we can get access of the i'th last element from
# i'th index.
# eg: [0,1,2,3,4,5] => 4th index can be accessed
# with the help of 1st index (i==n-i-1)
# where n is length of string
return all(s[i] == s[n - i - 1] for i in range(end))
def is_palindrome_recursive(s: str) -> bool: def is_palindrome_recursive(s: str) -> bool:
""" """
Return True if s is a palindrome otherwise return False. Return True if s is a palindrome otherwise return False.
@ -40,7 +61,7 @@ def is_palindrome_recursive(s: str) -> bool:
>>> all(is_palindrome_recursive(key) is value for key, value in test_data.items()) >>> all(is_palindrome_recursive(key) is value for key, value in test_data.items())
True True
""" """
if len(s) <= 1: if len(s) <= 2:
return True return True
if s[0] == s[len(s) - 1]: if s[0] == s[len(s) - 1]:
return is_palindrome_recursive(s[1:-1]) return is_palindrome_recursive(s[1:-1])
@ -58,9 +79,26 @@ def is_palindrome_slice(s: str) -> bool:
return s == s[::-1] return s == s[::-1]
def benchmark_function(name: str) -> None:
stmt = f"all({name}(key) is value for key, value in test_data.items())"
setup = f"from __main__ import test_data, {name}"
number = 500000
result = timeit(stmt=stmt, setup=setup, number=number)
print(f"{name:<35} finished {number:,} runs in {result:.5f} seconds")
if __name__ == "__main__": if __name__ == "__main__":
for key, value in test_data.items(): for key, value in test_data.items():
assert is_palindrome(key) is is_palindrome_recursive(key) assert is_palindrome(key) is is_palindrome_recursive(key)
assert is_palindrome(key) is is_palindrome_slice(key) assert is_palindrome(key) is is_palindrome_slice(key)
print(f"{key:21} {value}") print(f"{key:21} {value}")
print("a man a plan a canal panama") print("a man a plan a canal panama")
# finished 500,000 runs in 0.46793 seconds
benchmark_function("is_palindrome_slice")
# finished 500,000 runs in 0.85234 seconds
benchmark_function("is_palindrome")
# finished 500,000 runs in 1.32028 seconds
benchmark_function("is_palindrome_recursive")
# finished 500,000 runs in 2.08679 seconds
benchmark_function("is_palindrome_traversal")