看了题解,发现跟我想的不太一样,暴力解法即让字符串 needle与字符串 haystack 的所有长度为 m 的子串均匹配一次,匹配出错就跳出此子串的匹配,开始下一子串匹配。匹配成功,返回子串开始位置,失败,返回-1。
还有一个大名鼎鼎的KMP算法,但是看题解有些看不懂,过于理论化,问问GPT。
KMP(Knuth-Morris-Pratt)算法是一种用于在一个文本字符串(通常称为“主字符串”或“主文本”)中搜索一个词(通常称为“模式”或“子串”)的线性时间复杂度的算法。这种算法由Donald Knuth、James H. Morris和Vaughan Pratt三人共同发明,用于改进朴素的字符串搜索算法。
publicintstrStr(String haystack,String needle){int n = haystack.length(), m = needle.length();for(int i =0; i + m <= n ; i++){// 假设当前位置i是needle的起始位置,设置标志位flag为true boolean flag =true;// 在haystack中从位置i开始,检查长度为m的子串是否与needle相同 for(int j =0; j < m ; j++){// 如果在任意位置,haystack的字符与needle的字符不相同if(haystack.charAt(i + j)!= needle.charAt(j)){// 将标志位flag设为false,并跳出内部循环
flag =false;break;}}if(flag){return i;}}return-1;}
暴力解法的时间复杂度为:O(n * m) , 空间复杂度为:O(1)。
3.2 KMP解法
publicintstrStr(String haystack,String needle){int n = haystack.length(), m = needle.length();if( m ==0){return-1;}// 创建一个数组p,用于存储模式字符串needle的部分匹配表(或称为跳转表) int[] p =newint[m];// 初始化pi数组,并构建部分匹配表 // 变量i表示当前正在处理needle的哪个字符,j表示当前匹配到的最长公共前后缀的长度 for(int i =1,j =0; i < m; i ++){// 当j大于0且当前字符不匹配时,通过p数组回溯,寻找更短的前后缀匹配 while(j >0&& needle.charAt(i)!= needle.charAt(j)){
j = p[j -1];}// 如果当前字符匹配,或者j为0(即needle的第一个字符),则j自增 if(needle.charAt(i)== needle.charAt(j)){
j++;}// 更新p[i],表示当needle的第i个字符不匹配时,应该跳转到needle的第pi[i]个字符继续比较
p[i]= j;}// 接下来在主字符串haystack中搜索模式字符串needle // 变量i表示当前正在检查haystack的哪个字符,j表示当前匹配到的needle的字符索引 for(int i =0, j =0; i <n; i++){// 当j大于0且当前字符不匹配时,通过p数组回溯,寻找更短的前后缀匹配while(j >0&& haystack.charAt(i)!= needle.charAt(j)){
j = p[j -1];}// 如果当前字符匹配,j自增 if(haystack.charAt(i)== needle.charAt(j)){
j++;}// 如果j等于m,说明needle的所有字符都匹配了,返回needle在主字符串haystack中的起始位置 // 注意这里要减去needle的长度m-1,因为j是从1开始的if(j == m){return i - m +1;}}// 如果遍历完haystack后仍未找到与needle相同的子串,则返回-1 return-1;}