1.题目描述
实现 strStr() 函数。
给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。
示例 1:
输入: haystack = "hello", needle = "ll"
输出: 2
示例 2:输入: haystack = "aaaaa", needle = "bba"
输出: -1
说明:当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。
2.解题思路
KMP算法详解:
1.计算next数组
next数组即为match中相同前后缀的最长长度,next[ i ]为match[ 0 ~ i-1 ]中的,不算上i,并且不能是match[ 0 ~ i-1 ]本身。
eg: ptr 'ababaca',next数组有match长度位,即7位
对第一位'a'而言,没有相同前后缀,next[0] = -1
对前两位'ab'而言,next[1] = 0
对前三位'aba'而言,next[2] = 0
以此类推,next为[-1, 0, 0, 1, 2, 3, 0]。 注意‘ababa’中前后缀为aba和aba,前缀不包含最后一位,后缀不包含第0位,意味着前后缀不能等于总长。
这样做有什么好处呢?如下图所示
2.KMP
最上方为str,下方为match,3 4 为match在最后一位a之前的最长相同前后缀(3和4相同)。当match和str匹配到match的最后一位,发现match中最后一位为a,而str的对应为置为c。此时,1和2对应match的最长后缀3和4,所以1和2 相同。如果暴力匹配,应当取str[1]与match从[0]开始匹配,但是有了next,没有必要用暴力匹配的方式,因为中间一定匹配不到,直接在2的开始于3进行匹配即可,也就是说,比较2和3后面的是否相同
我们可以用i,j分别指向两个字符串的头部作为初始化,
当匹配失败时,j要移到的下一个位置k, 即next[j]。
KMP算法。其思想:“利用已知部分匹配这个有效信息,保持i指针不回溯,通过修改j指针(next[j]),让模式串尽量地移动到有效的位置。”
所以,next[j]的值(也就是k)表示,当P[j] != T[i]时,j指针的下一步移动位置。
这里为什么不是让j直接移动到0呢?
见下图:
参考:https://blog.csdn.net/CSDNwzl/article/details/88085359
参考:https://blog.csdn.net/u013185349/article/details/82316709
3.代码实现
方法1:
class Solution:
def getNextArray(self,nums):
if len(nums) < 2:
nextArray = []
nextArray.append(-1)
return nextArray
nextArray = [-1 for _ in range(len(nums))]
nextArray[1] = 0
cnt = 0
k = 2
while k < len(nums):
if nums[k-1] == nums[cnt]:
cnt += 1
nextArray[k] = cnt
k += 1
elif cnt > 0:
cnt = nextArray[cnt]
else:
nextArray[k] = 0
k += 1
return nextArray
#KMP
def strStr(self, haystack: str, needle: str) -> int:
nextArray = self.getNextArray(needle)
i = 0
j = 0
while i < len(haystack) and j < len(needle):
if haystack[i] == needle[j]:
i += 1
j += 1
elif nextArray[j] == -1:
i += 1
else:
j = nextArray[j]
if j == len(needle):
return i-j
else:
return -1
方法2:
class Solution(object):
def strStr(self, haystack, needle):
"""
:type haystack: str
:type needle: str
:rtype: int
"""
m=len(haystack)
n=len(needle)
if n==0:
return 0
if m<n:
return -1
for i in range(m-n+1):
j=0
for j in range(n):
if haystack[i+j]!=needle[j]:
break
if j == n-1:
return i
return -1