题目:给你两个字符串 haystack
和 needle
,请你在 haystack
字符串中找出 needle
字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle
不是 haystack
的一部分,则返回 -1
。
思路一:暴力解法,时间复杂度为 O((n-m+1)*m),其中 n 是 haystack
的长度,m 是 needle
的长度。
public int strStr(String haystack, String needle) {
int h=haystack.length();
int n=needle.length();
char[] ha=haystack.toCharArray();
char[] ne=needle.toCharArray();
for(int i=0;i<h-n+1;i++){//遍历haystack
int a=i,b=0;//a指向haystack中的元素,b指向needle中的元素
while(b<n&&ha[a]==ne[b]){//遍历needle
a++;
b++;
}
if(b==n)//第一次完全匹配
return i;
}
return -1;
}
思路二:KMP算法
KMP的主要思想是当出现字符串不匹配时,可以知道一部分之前已经匹配的文本内容,可以利用这些信息避免从头再去做匹配了。在算法中使用next数组实现该功能。
next数组就是一个前缀表,前缀表是用来回退的,它记录了模式串与主串(文本串)不匹配的时候,模式串应该从哪里开始重新匹配。
public int strStr(String haystack, String needle) {
int next[]=new int[needle.length()];
getNext(next,needle);
int j=0;
for(int i=0;i<haystack.length();i++){
while(j>0&&needle.charAt(j)!=haystack.charAt(i)){
j=next[j-1];
}
if(needle.charAt(j)==haystack.charAt(i)){
j++;
}
if(j==needle.length()){//完全匹配
return i-needle.length()+1;
}
}
return -1;
}
public void getNext(int[] next,String needle){
int j=0;//前缀末尾,同时也代表i及i之前的字符串的最长相等前后缀的长度
next[0]=0;
for(int i=1;i<needle.length();i++){//i为后缀末尾,开始计算next[1]...
while(j>0&&needle.charAt(i)!=needle.charAt(j)){
j=next[j-1];//如果不相等则j回退,注意这个回退是连续的,不是只回退一次
}
if(needle.charAt(i)==needle.charAt(j)){
j++;
}
next[i]=j;//更新next数组
}
}