99def kmp (s : int , pattern : int ) -> int :
1010 m = len (pattern )
1111 partial_match_table = _get_partial_match_table (pattern )
12+ print (partial_match_table )
1213 j = 0
1314 for i in range (len (s )):
14- while j and s [i ] != pattern [j ]:
15- j = partial_match_table [j - 1 ] + 1
15+ while j >= 0 and s [i ] != pattern [j ]:
16+ j = partial_match_table [j ]
1617 j += 1
1718 if j == m :
1819 return i - m + 1
1920 return - 1
2021
2122
2223def _get_partial_match_table (pattern : int ) -> List [int ]:
23- # Denote pi^k (i) as pi applied to i for k times,
24- # i.e., pi^2 (i) = pi(pi (i)).
24+ # Denote πᵏ (i) as π applied to i for k times,
25+ # i.e., π² (i) = π(π (i)).
2526 # Then we have the result:
26- # pi (i) = pi^k (i-1) + 1,
27+ # π (i) = πᵏ (i-1) + 1,
2728 # where k is the smallest integer such that
28- # pattern[pi^k(i-1)+1] == pattern[i].
29+ # pattern[πᵏ(i-1)+1] == pattern[i].
30+
31+ # The value of π means the maximum length
32+ # of proper prefix/suffix.
33+ # The index of π means the length of the prefix
34+ # considered for pattern.
35+ # For example, π[2] means we are considering the first 2 characters
36+ # of the pattern.
37+ # If π[2] == 1, it means for the prefix of the pattern, P[0]P[1],
38+ # it has a maximum length proper prefix of 1, which is also the
39+ # suffix of P[0]P[1].
40+ # We also add a π[0] == -1 for easier handling of boundary
41+ # condition.
2942
3043 m = len (pattern )
31- pi = [0 ] * m
32- pi [0 ] = k = - 1 # We use k here to represent pi^k (i)
33- for i in range (1 , m ):
34- while k >= 0 and pattern [k + 1 ] != pattern [i ]:
35- k = pi [k ]
44+ π = [0 ] * ( m + 1 )
45+ π [0 ] = k = - 1 # We use k here to represent πᵏ (i)
46+ for i in range (1 , m + 1 ):
47+ while k >= 0 and pattern [k ] != pattern [i - 1 ]:
48+ k = π [k ]
3649 k += 1
37- pi [i ] = k
38- return pi
50+ π [i ] = k
51+ return π
3952
4053
4154if __name__ == "__main__" :
4255
4356 s = "abc abcdab abcdabcdabde"
4457 pattern = "bcdabd"
58+ print (kmp (s , pattern ), s .find (pattern ))
59+
60+ s = "hello"
61+ pattern = "ll"
4562 print (kmp (s , pattern ), s .find (pattern ))
0 commit comments