28. 找出字符串中第一个匹配项的下标
28.找到字符串中第一个匹配项的下标
KMP算法
原串:sadbutsad
匹配串:sad
构造next数组其实就是计算模式串s的前缀表的过程。与原串是无关的
关于最长公共前缀和最长公共后缀:
前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串。
后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串。
next数组和最长公共前后缀的关系:最长公共部分的程度来确定next[i]
比如字符串 : “aabaaf”
用KMP实现的代码,用滑动窗口还不会,最近实习好累
class Solution {
public int strStr(String h, String n) {
//1.滑动窗口
//2.KMP算法
if(n.length()==0){
return 0;
}
int[] next=new int[n.length()];
getNext(next,n);
int j=-1;//哨兵
for(int i=0;i<h.length();i++){
while(j>=0&&h.charAt(i)!=n.charAt(j+1)){
//遇到模式串和原串不匹配的字符了,就寻找模式串要跳到的下一个位置,下标
j=next[j];
}
if(h.charAt(i)==n.charAt(j+1)){
j++;
}
if(j==n.length()-1){//j把模式串n遍历完了,返回原串刚开始匹配的索引值
return (i-n.length()+1);
}
}
return -1;
}
//next数组只和needle有关
public void getNext(int[] next,String s){
//双指针来构建next数组
int j=-1;
next[0]=j;
//每次for循环最后j的值就是,i所指向的字符与原串无法匹配时下一次要跳到的位置
for(int i=1;i<s.length();i++){
while(j>=0&&s.charAt(i)!=s.charAt(j+1)){//比如aab,此时i指向b,j指向第一个a
j=next[j];//这是最为关键的
}
if(s.charAt(i)==s.charAt(j+1)){
j++;
}
//上面决定好j的最终位置然后赋值给next[i]
next[i]=j;//如果当遍历模式串的下标i位置时不匹配,那么将遍历模式串的指针移动下标为next[i]的位置
}
}
//滑动窗口
}
459. 重复的子字符串
459.重复的子字符串(二刷三刷)
这道题真的没有思路,还是要二刷
实现一个 高效的算法来判断 一个字符串中是否出现另一个字符串是很复杂的,这里就涉及到了KMP算法。
数组长度减去最长相同前后缀的长度相当于是第一个周期的长度,也就是一个周期的长度,如果这个周期可以被整除,就说明整个数组就是这个周期的循环。
如字符串:"abc abc abc abc"的最长公共前后缀是"abc abc abc"
class Solution {
public boolean repeatedSubstringPattern(String s) {
int len=s.length();
// 原串加个空格(哨兵),使下标从1开始,这样j从0开始,也不用初始化了
s=" "+s;
char[] chars=s.toCharArray();
int[] next=new int[len+1];
//构造next数组
for(int i=2,j=0;i<=len;i++){
//匹配不成功,j回到前一位置next数组所对应的值
while(j>0&&chars[i]!=chars[j+1]){
j=next[j];
}
//匹配成功,j往后移
if(chars[i]==chars[j+1]){j++;}
next[i]=j;
}
//判断
if(next[len]>0&&len%(len-next[len])==0){
return true;
}
return false;
}
}
/***
String str = s + s;
return str.substring(1, str.length() - 1).contains(s);
作者:Goodlucky
链接:https://leetcode.cn/problems/repeated-substring-pattern/solutions/114572/jian-dan-ming-liao-guan-yu-javaliang-xing-dai-ma-s/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
*/