马拉车算法:在O(n)时间内找到回文串长度
首先处理输入的字符串
然后从0一直运行到len-2
r存臂长伸到的最右的位置,mid为这个中心点的下标
每次考察一个点,如果这个点在r里面,找对称点,最长情况之下就是r-i的长度,所以用min;
int longestPalindrome(string s) {
string new_str = "";
new_str += "@";
for (int i = 0;i < str.length(); i++) {
new_str += "#";
new_str += str[i];
}
new_str += "#";
new_str += "$";
cout << new_str << endl;
//new_str 存储 扩充后的字符串,如 @#a#b#a#$
int len = new_str.length();
int r = 0, mid = 0, ans = 0;//r 表示目前最右回文子串半径,mid则是该字串的中心下标,ans存储最长回文子串长度。
for (int i = 1;i < len-1; i++) {
if (i < r) {
Len[i] = min(r - i, Len[2*mid-i]);
}
else Len[i] = 1;
while (new_str[i+Len[i]] == new_str[i-Len[i]]) {
Len[i]++;
}
if ((i+Len[i]) > r) {
r = i + Len[i]-1;
mid = i;
}
ans = max(ans, (Len[i] - 1));
}
return ans;
}
KMP算法通过计算子串的最长公共前后缀,减少匹配次数
先计算子串的最长公共前后缀:
计算过程与KMP算法类似,先初始next【0】=-1;
j从0到最后遍历子串
k最初指向-1,循环中只要k指向-1,或者匹配上,i++,j++,并赋值next【j】
r如果不匹配,k更新为next【k】,前面的前缀就相当于子串
kmp算法:同样i指向子串,j指向主串,初始化都为0;循环过程中只要j=-1或者匹配上了,就加加
没匹配上子串j更新为next【j】;
一直到子串匹配完输出位置
#include<bits/stdc++.h>
using namespace std;
const int N=1000;
int nextt[N];
string s="",S="";//主串和子串
//nextt数组是i前面的字符串最长相等前后缀的长度
//同时也是当i位置匹配不成功的时候从子串的nextt[i]位置开始匹配
//求的是子串的最长相等前后缀
void Next()
{
int k=-1,j=0;
nextt[0]=-1;
while(j<S.length()-1)
{
cout<<"next";
//从0号位置开始
//如果是第一次操作,因为1号前面只有0号,最长相等前后缀==0
if(k==-1||S[k]==S[j])
{
k++;
j++;
nextt[j]=k;
}
else
{
k=nextt[k];
//发现匹配不成功了
//求nextt的过程也就是一个字符串的后缀和前面匹配的过程
//前面的字符串就是子串
//发现匹配不成功了,而前面的匹配是成功的,
//从主串的nextt[k]位置开始重新匹配
}
}
}
int main()
{
cin>>S>>s;//子串与主串
Next();
int i=0,j=0;
while(i<s.length()&&j<S.length())
{
cout<<"main";
if(j==-1||s[i]==S[j])
{
i++;
j++;
//cout<<i<<" "<<j<<endl;
}
else
{
j=nextt[j];
//cout<<i<<" "<<j<<endl;
}
}
if(j>s.length())
{
// cout<<j<<endl;
// cout<<S.length()<<endl;
int num=j-S.length();
cout<<num<<endl;
}
}