2023-10-02 05:18:50 +00:00
|
|
|
# https://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm
|
|
|
|
|
2023-10-02 05:20:39 +00:00
|
|
|
|
2023-10-02 05:18:50 +00:00
|
|
|
def knuth_morris_pratt(text: str, pattern: str) -> list[int]:
|
|
|
|
"""
|
|
|
|
Knuth-Morris-Pratt (KMP) string search algorithm in Python.
|
|
|
|
|
|
|
|
:param text: The text in which to search for the pattern.
|
|
|
|
:param pattern: The pattern to search for in the text.
|
|
|
|
:return: A list of starting positions where the pattern is found in the text.
|
|
|
|
|
|
|
|
Examples:
|
|
|
|
>>> knuth_morris_pratt("ABABDABACDABABCABAB", "ABABCABAB")
|
|
|
|
[10]
|
|
|
|
>>> knuth_morris_pratt("ABCABCABCABCABC", "ABC")
|
|
|
|
[0, 3, 6, 9, 12]
|
|
|
|
>>> knuth_morris_pratt("AAAAAA", "AA")
|
|
|
|
[0, 1, 2, 3, 4]
|
|
|
|
>>> knuth_morris_pratt("ABCDEF", "XYZ")
|
|
|
|
[]
|
|
|
|
|
|
|
|
"""
|
2023-10-02 05:20:39 +00:00
|
|
|
|
2023-10-02 05:18:50 +00:00
|
|
|
def build_prefix_table(pattern: str) -> list[int]:
|
|
|
|
"""
|
|
|
|
Build the prefix table for the given pattern.
|
|
|
|
|
|
|
|
:param pattern: The pattern for which to build the prefix table.
|
|
|
|
:return: The prefix table, which is a list of integers.
|
|
|
|
|
|
|
|
Examples:
|
|
|
|
>>> build_prefix_table("ABABCA")
|
|
|
|
[0, 0, 1, 2, 3, 0]
|
|
|
|
>>> build_prefix_table("ABCABC")
|
|
|
|
[0, 0, 0, 1, 2, 3]
|
|
|
|
>>> build_prefix_table("AAAAAA")
|
|
|
|
[0, 1, 2, 3, 4, 5]
|
|
|
|
>>> build_prefix_table("XYZ")
|
|
|
|
[0, 0, 0]
|
|
|
|
|
|
|
|
"""
|
|
|
|
prefix_table = [0] * len(pattern)
|
|
|
|
j = 0
|
|
|
|
for i in range(1, len(pattern)):
|
|
|
|
while j > 0 and pattern[i] != pattern[j]:
|
|
|
|
j = prefix_table[j - 1]
|
|
|
|
if pattern[i] == pattern[j]:
|
|
|
|
j += 1
|
|
|
|
prefix_table[i] = j
|
|
|
|
return prefix_table
|
|
|
|
|
|
|
|
prefix_table = build_prefix_table(pattern)
|
|
|
|
positions = []
|
|
|
|
j = 0
|
|
|
|
for i in range(len(text)):
|
|
|
|
while j > 0 and text[i] != pattern[j]:
|
|
|
|
j = prefix_table[j - 1]
|
|
|
|
if text[i] == pattern[j]:
|
|
|
|
j += 1
|
|
|
|
if j == len(pattern):
|
|
|
|
positions.append(i - j + 1)
|
|
|
|
j = prefix_table[j - 1]
|
|
|
|
return positions
|
|
|
|
|
2023-10-02 05:20:39 +00:00
|
|
|
|
2023-10-02 05:18:50 +00:00
|
|
|
if __name__ == "__main__":
|
|
|
|
text = input("Enter the text: ")
|
|
|
|
pattern = input("Enter the pattern to search for: ")
|
|
|
|
positions = knuth_morris_pratt(text, pattern)
|
|
|
|
if positions:
|
|
|
|
print(f"Pattern found at positions: {positions}")
|
|
|
|
else:
|
|
|
|
print("Pattern not found in the text.")
|