Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/source/pydatastructs/strings/algorithms.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Algorithms
==========

.. autofunction:: pydatastructs.find
.. autofunction:: pydatastructs.find
.. autofunction:: pydatastructs.manacher
Binary file not shown.
Binary file not shown.
Binary file not shown.
3 changes: 2 additions & 1 deletion pydatastructs/strings/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
__all__.extend(trie.__all__)

from .algorithms import (
find
find,
manacher
)

__all__.extend(algorithms.__all__)
54 changes: 53 additions & 1 deletion pydatastructs/strings/algorithms.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
Backend, raise_if_backend_is_not_python)

__all__ = [
'find'
'find',
'manacher'
]

PRIME_NUMBER, MOD = 257, 1000000007
Expand Down Expand Up @@ -83,6 +84,57 @@ def find(text, query, algorithm, **kwargs):
%(algorithm))
return getattr(algorithms, func)(text, query)

def manacher(text: str) -> str:
"""
Finds the longest palindromic substring in the given text using Manacher's algorithm.

Parameters
==========
text: str
The input string in which to find the longest palindromic substring.

Returns
=======
str
The longest palindromic substring found in the input text.

Examples
========
>>> manacher("abacdfgdcaba")
'aba'
>>> manacher("forgeeksskeegfor")
'geeksskeeg'
"""
if not text:
return ""

processed_text = "#" + "#".join(text) + "#"
n = len(processed_text)
lps = [0] * n
center = 0
right = 0
max_len = 0
max_center = 0

for i in range(n):
if i < right:
lps[i] = min(right - i, lps[2 * center - i])

while (i + lps[i] + 1 < n and i - lps[i] - 1 >= 0 and
processed_text[i + lps[i] + 1] == processed_text[i - lps[i] - 1]):
lps[i] += 1

if lps[i] > max_len:
max_len = lps[i]
max_center = i

if i + lps[i] > right:
center = i
right = i + lps[i]

start = (max_center - max_len) // 2
end = start + max_len
return text[start:end]

def _knuth_morris_pratt(text, query):
if len(text) == 0 or len(query) == 0:
Expand Down
23 changes: 22 additions & 1 deletion pydatastructs/strings/tests/test_algorithms.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from pydatastructs.strings import find
from pydatastructs.strings import find, manacher

import random, string

Expand All @@ -14,6 +14,27 @@ def test_bm():
def test_zf():
_test_common_string_matching('z_function')

def test_manacher():
"""
Test cases for Manacher's Algorithm to find the longest palindromic substring.
"""
test_cases = [
# (input_text, expected_longest_palindrome)
("", ""), # Empty string
("a", "a"), # Single character
("abacdfgdcaba", "aba"), # Odd-length palindrome
("abba", "abba"), # Even-length palindrome
("forgeeksskeegfor", "geeksskeeg"), # Long palindrome
("abcde", "a"), # No palindrome longer than 1
("racecar", "racecar"), # Full string is a palindrome
("abacaba", "abacaba"), # Overlapping palindromes
("abacabacabb", "bacabacab"), # Complex case
]

for text, expected in test_cases:
result = manacher(text)
assert result == expected, f"Failed for input: {text}. Expected: {expected}, Got: {result}"

def _test_common_string_matching(algorithm):
true_text_pattern_dictionary = {
"Knuth-Morris-Pratt": "-Morris-",
Expand Down
Binary file not shown.
Binary file not shown.
Loading