686. Repeated String Match
Problem
Given two strings, A and B. How many times we need to repeat A, so that B is a substring of A.
Solution
Repeat A until the string is as long as 2*len(B) - 1, which is the maximum length needed to find the answer. Use Rabin-Karp to hash the first len(B) chars in A, and sliding window one char by one char to the right. Compare each of the hash value of the substrings to the hash value of B. If not equal, then the substring is not B. If equal, we check char by char to see if the substring is B or not.
Algorithms
Rabin-Karp
Code
# Simple solution
class Solution:
def repeatedStringMatch(self, A: str, B: str) -> int:
x = (len(B) - 1) // len(A) + 1
if B in A * x:
return x
if B in A * (x + 1):
return x + 1
return -1
# Karp-Rabin
MOD = int((10 ** 9) + 7)
BASE = 26
class Solution:
def validate(self, index, A, B):
for i in range(len(B)):
if index - i < 0:
break
if A[(index - i) % len(A)] != B[-1 - i]:
return False
return True
def repeatedStringMatch(self, A: str, B: str) -> int:
b_value = 0
for char in B:
b_value = (b_value * BASE) % MOD + ord(char) - ord('a')
b_value %= MOD
hash_value = 0
multiplier = 1
for i in range(len(B)):
multiplier = (multiplier * BASE) % MOD
index = 0
while index < max(len(B) * 2, len(A) * 2):
hash_value = (ord(A[index % len(A)]) - ord('a') + (hash_value * BASE) % MOD) % MOD
if index >= len(B):
hash_value -= ((ord(A[(index - len(B)) % len(A)]) - ord('a')) * multiplier) % MOD
hash_value = (hash_value + MOD) % MOD
if hash_value == b_value and index >= len(B) - 1:
if self.validate(index, A, B):
return index // len(A) + 1
index += 1
return -1
# KMP
class Solution:
def repeatedStringMatch(self, A: str, B: str) -> int:
link = [-1] * (len(B) + 1)
for j in range(len(B) - 1):
i = j
while i != -1 and B[j + 1] != B[link[i] + 1]:
i = link[i]
link[j + 1] = link[i] + 1
b_index = -1
for i in range(-1, len(A) + len(B)):
if b_index == len(B) - 1:
return i // len(A) + 1
while A[(i + 1) % len(A)] != B[b_index + 1] and b_index != -1:
b_index = link[b_index]
if A[(i + 1) % len(A)] == B[b_index + 1]:
b_index += 1
continue
return -1