|
| 1 | +""" |
| 2 | +https://cp-algorithms.com/string/prefix-function.html |
| 3 | +
|
| 4 | +Prefix function Knuth–Morris–Pratt algorithm |
| 5 | +
|
| 6 | +Different algorithm than Knuth-Morris-Pratt pattern finding |
| 7 | +
|
| 8 | +E.x. Finding longest prefix which is also suffix |
| 9 | +
|
| 10 | +Time Complexity: O(n) - where n is the length of the string |
| 11 | +""" |
| 12 | + |
| 13 | + |
| 14 | +def prefix_function(input_string: str) -> list: |
| 15 | + """ |
| 16 | + For the given string this function computes value for each index(i), |
| 17 | + which represents the longest coincidence of prefix and sufix |
| 18 | + for given substring (input_str[0...i]) |
| 19 | +
|
| 20 | + For the value of the first element the algorithm always returns 0 |
| 21 | +
|
| 22 | + >>> prefix_function("aabcdaabc") |
| 23 | + [0, 1, 0, 0, 0, 1, 2, 3, 4] |
| 24 | + >>> prefix_function("asdasdad") |
| 25 | + [0, 0, 0, 1, 2, 3, 4, 0] |
| 26 | + """ |
| 27 | + |
| 28 | + # list for the result values |
| 29 | + prefix_result = [0] * len(input_string) |
| 30 | + |
| 31 | + for i in range(1, len(input_string)): |
| 32 | + |
| 33 | + # use last results for better performance - dynamic programming |
| 34 | + j = prefix_result[i - 1] |
| 35 | + while j > 0 and input_string[i] != input_string[j]: |
| 36 | + j = prefix_result[j - 1] |
| 37 | + |
| 38 | + if input_string[i] == input_string[j]: |
| 39 | + j += 1 |
| 40 | + prefix_result[i] = j |
| 41 | + |
| 42 | + return prefix_result |
| 43 | + |
| 44 | + |
| 45 | +def longest_prefix(input_str: str) -> int: |
| 46 | + """ |
| 47 | + Prefix-function use case |
| 48 | + Finding longest prefix which is sufix as well |
| 49 | +
|
| 50 | + >>> longest_prefix("aabcdaabc") |
| 51 | + 4 |
| 52 | + >>> longest_prefix("asdasdad") |
| 53 | + 4 |
| 54 | + >>> longest_prefix("abcab") |
| 55 | + 2 |
| 56 | + """ |
| 57 | + |
| 58 | + # just returning maximum value of the array gives us answer |
| 59 | + return max(prefix_function(input_str)) |
| 60 | + |
| 61 | + |
| 62 | +if __name__ == "__main__": |
| 63 | + import doctest |
| 64 | + |
| 65 | + doctest.testmod() |
0 commit comments