思路:
1、朴素解法:两个for循环,原串的每个字符作为出发点,与匹配串从首位开始的字符进行匹配
若都匹配,返回本次原串的出发点
若有一个不匹配,原串出发点右移一位,重新匹配
时间复杂度O(n*m)
class Solution:
def strStr(self, haystack: str, needle: str) -> int:
n=len(haystack)
m=len(needle)
if m==0:
return 0
if n==0:
return -1
for i in range((n-m)+1):
flag=True
for j in range(m):
if haystack[i+j] != needle[j]:
flag=False
break
if flag:
return i
return -1
2、KMP算法
前缀表,next数组,时间复杂度O(n+m)
- 前缀表:记录下标i之前(包括i)的字符串中,最长相等前后缀;当字符不匹配,按前缀表记录的下标,直接跳转值对应字符,避免从头匹配。
- 前缀:不包含最后一个字符的所有以第一个字符开头的连续子串
- 后缀:不包含第一个字符的所以以最后一个字符结尾的连续子串
- next数组:有两种:一种是前缀表;另一种是前缀表统一减1(初始位置-1)
- 构造next数组:即前缀表,
- 初始化:两个指针,j指向前缀的结束位置,i指向后缀的结束位置
- 处理前后缀不同的情况;
- 处理前后缀相同的情况
class Solution:
def strStr(self, haystack: str, needle: str) -> int:
#KMP算法
n=len(haystack)
m=len(needle)
if m==0:
return 0
if n==0:
return -1
next=['']*m
next=self.getNext(next,needle)
j=0
for i in range(n):
while j > 0 and haystack[i]!=needle[j]:
#字符不等,回退
j=next[j-1]
if haystack[i]==needle[j]:
j+=1
if j==m:
return (i-m+1)
return -1
def getNext(self,next,needle):
#前缀表不减1
j=0
next[0]=0
#i从1开始
for i in range(1,len(needle)):
#j要大于0,因为下面有j-1作为下标取值的情况
while j > 0 and needle[i] != needle[j]:
#找前一位的对应回退位置
j=next[j-1]
if needle[i] == needle[j]:
j+=1
next[i]=j
return next
常见误区:
1)死记硬背KMP算法
2)代码不规范
变量名要友好、二元运算符两边都要加空格、要有缩进和括号
3)没有异常检测和边界处理
下标访问不能越界、参数检查等
4)不主动沟通
要让面试官知道你的意图
5)无测试案例
写出合理的testcase
6)注意边界
原串i<(n-m)+1,匹配串j<m
不要用j==m判断,因为python的for循环不同于java
不要用j==(m-1)判断,无法通过用例'abc','c',即匹配串只有一个字符时,结果错
用flag=True判断,用例可全过