题目描述:给定主字符S与模式字符串P,判断P是否是S的子串,如果是,那么找出P在S中第一次出现的下标。
分析与解答:对于字符串的匹配,最直接的方法就是逐个比较字符串中的字符,这种方法比较容易实现,但是效率也比较低下。对于这种字符串匹配的问题,除了最常见的直接比较法外,经典的KMP算法也是不二选择,它能够显著的提高运行效率。
方法一:直接计算法
def match(s, p):
# 检查参数的合理性
if s == None or p == None:
print("参数不合理")
return -1
slen = len(s)
plen = len(p)
# p肯定不是S的子串
if slen < plen:
return -1
i = 0
j = 0
while i < slen and j < plen:
if list(s)[i] == list(p)[j]:
# 如果相同,那么继续比较后面的字符
i += 1
j += 1
else:
# 后退回去重新比较
i = i - j + 1
j = 0
if i > slen - plen:
return -1
# 匹配成功
if j >= plen:
return i - plen
return -1
if __name__ == "__main__":
s = "xyzabcd"
p = "abc"
print(match(s, p))
方法二:KMP算法
def getNext(p, nexts):
i = 0
j = -1
nexts[0] = -1
while i < len(p):
if j == -1 or list(p)[i] == list(p)[j]:
i += 1
j += 1
nexts[i] = j
else:
j = nexts[j]
def match(s, p, nexts):
# 检查参数的合理性,s的长度一定不会小于p的长度
if s == None or p == None:
print("参数不合理")
return -1
slen = len(s)
plen = len(p)
# p肯定不是s的子串
if slen < plen:
return -1
i = 0
j = 0
while i < slen and j < plen:
print("i="+str(i)+","+"j="+str(j))
if j == -1 or list(s)[i] == list(p)[j]:
# 如果相同,那么继续比较后面的字符
i += 1
j += 1
else:
# 主串i不需要回溯,从next数组中找出比较的模式串的位置j
j = nexts[j]
# 匹配成功
if j >= plen:
return i-plen
return -1
if __name__ == "__main__":
s = "abababaabcbcbcb"
p = "abaabc"
lens = len(p)
nexts = [0]*(lens + 1)
getNext(p, nexts)
print("next数组为:"+str(nexts[0]))
i = 1
while i < lens - 1:
print(","+str(nexts[i]))
i += 1
print('\n')
print("匹配结果为:"+str(match(s,p,nexts)))