这里写目录标题
STL(字符串)
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll int maxn = 3e6+10;
const ll int N = 4e6+10;
#define bug(x) cout<<#x<<" == "<<x<<endl;
int main()
{
string st1("babbabab");
string st2("aabcbcabcbabcc");
string str1 = "abc";
///查找字符串:
///find-从指定位置起向后查找,直到串尾
///1.默认从位置0(即第1个字符)开始查找
cout << st1.find('a') << endl;
///2.在st1中,从位置2(b,包括位置2)开始,查找a,返回首次匹配的位置
cout << st1.find('a', 2) << endl;
///3.从st2的位置2(b)开始匹配,返回第一次成功匹配时匹配的串(abc)的首字符在st2中的位置,失败返回-1
cout << st2.find(str1, 2) << endl;
///4.取abcdefg得前3个字符(abc)参与匹配,相当于st2.find("abc", 2)
cout << st2.find("abcdefg", 2, 3) << endl;
///删除字符串
cout<<st2.erase(1,2)<<endl;
///反转字符串
reverse(str1.begin(), str1.end());
cout<<str1<<endl;
///截取子串
cout<<st1.substr(2,5)<<endl;
cout<<st1.substr(2)<<endl;
cout<<st1.substr()<<endl;
///交换字符串
swap(st1,st2);
cout<<st1<<endl;
st1.swap(st2);
cout<<st1<<endl;
///比较字符串
///int compare(const char *s) const;
///int compare(int pos, int n,const char *s) const;
///int compare(int pos, int n,const char *s, int pos2) const;
///int compare(int pos, int n,const string &s,int pos2=0,int n2=posn2)const;
///比较当前字符串从pos开始的n个字符组成的字符串与s中pos2开始的n2个字符组成的字符串的大小
///compare函数在>时返回1,<时返回-1,==时返回0
cout<<st1.compare(1,2,st2)<<endl;
cout<<st1.compare(1,2,st2,4,2)<<endl;
}
tire树
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll int maxn = 4e6+10;
const ll int N = 1e5+10;
#define bug(x) cout<<#x<<"=="<<x<<endl;
string a;
int tree[maxn*4][30]={0};
int way1[maxn*4] = { 0 };
int way2[maxn*4] = { 0 };
///操作各种各样,在建树的时候修改即可
int tot=0;
void add(string a)
{ji
int h=0;
for(int i=0;i<a.length();i++)
{
int id=a[i]-'a';
if(!tree[h][i])
{
tot++;
tree[h][i] = tot;
}
h = tree[h][i];
way2[h]++;
///记录每一个单词的前缀字符串数目
}
way2[h]++;///记录每一个单词的数量
}
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a;
add(a);
}
}
AC自动机
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll int maxn = 4e6+10;
const ll int N = 4e6+10;
#define bug(x) cout<<#x<<"=="<<x<<endl;
struct AC_automaton
{
int tr[N][26],cnt;///tire
int e[N];///该单词出现次数
int fail[N];
void add(char s[])
{
int p=0;
for(int i=0; s[i]; i++)
{
int k = s[i]-'a';
if(!tr[p][k])cnt++,tr[p][k]=cnt;
p = tr[p][k];
}
e[p]++;
}
void build()
{
queue<int> q;
memset(fail,0,sizeof(fail));
for(int i=0; i<26; i++)if(tr[0][i])q.push(tr[0][i]);
while(!q.empty())
{
int k=q.front();
q.pop();
for(int i=0;i<26;i++)
{
if(tr[k][i])
{
fail[ tr[k][i] ] = tr[ fail[k] ][i];
q.push( tr[k][i] );
}
else
{
tr[k][i] = tr[ fail[k] ][i];
}
}
}
}
int query(char *s)
{
int p=0;
int res=0;
for(int i=0;s[i];i++)///枚举这个单词的所有前缀 在前面的树里有没有出现过
{
int k = s[i]-'a';
p = tr[p][k];
for(int j=p;j&&~e[j];j=fail[j])
{
///判断e[j]是不是为-1
res += e[j];
e[j] = -1;
}
}
return res;
}
};
AC_automaton a;
char b[maxn];
int main()
{
int n;
cin>>n;
for(int i=1; i<=n; i++)
{
getchar();
cin>>b;
a.add(b);
}
a.build();
getchar();
cin>>b;
cout<<a.query(b)<<endl;
}
KMP
string a;
int nextt[maxn] = { -1 };
///表示了字符串1~i最大前缀长度
int main()
{
cin>>a;
nextt[0] = -1;
int j=0;
///当前参与匹配的字符串为1~j;
int k=-1;///当前正在匹配的字符串前缀位置
while(j<a.length())
{
if(k==-1||a[k]==a[j])
{
///当k等于的0的时候 说明一直回溯到了字符串最前端,前面都没有匹配的
///所以next[j] = 0;
///当A[j]和a[k]匹配的时候,说明next[j+1]前的最大前缀和后缀相同长度为k;
k++;
j++;
nextt[j] = k;
}
else
{
k = nextt[k];
///当前位置不行,就跳转到上一个
}
}
}
kuangbin kmp
(HDU)Number Sequence
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll int maxn = 3e6+10;
const ll int N = 4e6+10;
#define bug(x) cout<<#x<<" == "<<x<<endl;
int a[maxn] = { 0 };
int nextt[maxn] = { 0 };
int b[maxn] = { 0 };
int n,m;
void get_kmp()
{
memset(nextt,0,sizeof(nextt));
nextt[0] = -1;
int i=-1;
int j=0;
while(j<m)
{
if( i==-1 || a[i]==a[j] )
{
j++;
i++;
nextt[j]=i;
}
else
{
i=nextt[i];
}
}
}
int get_same()
{
int ans = 0;
int i=0;
int j=0;
while(j<m&&i<n)
{
if(j==-1||b[i]==a[j])
{
i++;
j++;
}
else
{
j=nextt[j];
}
}
if(j==m)
{
return i-j+1;
}
else
{
return -1;
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&n,&m);
for(int i=0;i<n;i++)
{
scanf("%d",&b[i]);
}
for(int i=0;i<m;i++)
{
scanf("%d",&a[i]);///a为模式串
}
if(m>n)
{
printf("-1\n");
continue;
}
get_kmp();
cout<<get_same()<<'\n';
}
}
(dp+kmp)Count the string
不重合的字符串kmp
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll int maxn = 2e5+10;
const ll int N = 4e6+10;
#define bug(x) cout<<#x<<" == "<<x<<endl;
typedef pair<int,int> pp;
char zmb[maxn] = { 0 };
char fm[maxn] = { 0 };
char s[maxn] = { 0 };
int nextt[maxn] = { 0 };
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%s",zmb);
scanf("%s",s);
nextt[0] = -1;
int i=-1;
int j=0;
int len=strlen(s);
while(j<len)
{
if(i==-1||s[i]==zmb[ s[j]-'a' ])
{
i++;
j++;
nextt[j] = i;
}
else
{
i = nextt[i];
}
}
int now=len;
while(nextt[now]*2>len)
{
now=nextt[now];
}
for(int i=0; i<26; i++)
{
fm[ zmb[i]-'a' ]=i+'a';
}
printf("%s",s);
for(int i=nextt[now]; i<len-nextt[now]; i++)
{
printf("%c",fm[ s[i]-'a' ]);
}
printf("\n");
}
}
马拉车算法(字符串+动态规划)
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll int maxn = 3e7+10;
const ll int N = 4e6+10;
#define bug(x) cout<<#x<<" == "<<x<<endl;
int p[maxn] = { 0 };
///以i为中心的最大回文字符串(此时的字符串是处理过的)到左端点的距离 + 1
int id=0;///当前计算的最大长度的字符串的中心
int maxx=0;///以id为中心的最大回文字符串(此时的字符串是处理过的)的右端点+1
int main()
{
string a;
string b;
cin>>a;
b += '$';
for(int i=0;i<a.size();i++)
{
b += '#';
b += a[i];
}
b += '#';
int len=b.length();
///预处理,将每一个字符串变成奇数串 使子串的中心固定
int ans=0;
for(int i=1;i<len;i++)
{
if(maxx>i)
{
p[i] = min(maxx-i,p[2*id-i]);
///当maxx>i的时候 说明 以id为中心,左右两端长度为maxx-id的字符串里面包含了b[i];
///说明 id-(i-id)和b[i]是这个字符串里面两个对称点,
///而且i-(i-maxx)~maxx部分也和2*id-maxx~2*id-i+(i-maxx)相同
///所以如果p[2*id-1]<=maxx-i -> p[i]==p[2*id-1];
///如果p[2*id-1]>maxx-i,只能截取肯定相同的部分即maxx-i;
}
else
{
p[i] = 1;
}
while(b[ i-p[i] ] ==b[ i+p[i] ] )
{
p[i]++;
}
if(i+p[i]>maxx)
{
maxx = i + p[i];
id = i;
}
ans=max(p[i]-1,ans);
}
printf("%d\n",ans);
}
后缀数组
后缀排序
洛谷模板题
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll int maxn = 3e6+10;
const ll int N = 4e6+10;
#define bug(x) cout<<#x<<" == "<<x<<endl;
int rankk[maxn] = { 0 };
int tmp[maxn] = { 0 };
int sa[maxn] = { 0 };
int ans[maxn] = { 0 };
string a;
int k = 0;
int n;
bool cmp(int i,int j)
{
if(rankk[i] != rankk[j])
{
return rankk[i]<rankk[j];
}
else
{
int ri = i+k<=n ? rankk[i+k]:-1;
int rj = j+k<=n ? rankk[j+k]:-1;
return ri < rj;
}
}
int main()
{
cin>>a;
n = a.length();
for(int i=0; i<n; i++)
{
sa[i] = i;
rankk[i] = a[i];
}
sa[n] = n;
rankk[n] = -1;
for(k=1; k<=n; k*=2)
{
sort(sa,sa+1+n,cmp);
tmp[sa[0]] = 0;
for (int i=1; i <= n; i++)
tmp [sa[i]] = tmp[sa [i - 1]] + (cmp(sa[i-1],sa[i])?1 :0);
for(int i=0; i<=n; i++)
{
rankk[i]=tmp[i];
}
}
for(int i=0;i<n;i++)
{
ans[ tmp[i] ]= i+1;
}
for(int i=1;i<=n;i++)
{
printf("%d ",ans[i]);
}
printf("\n");
}
基于后缀数组的字符串匹配
bool contain(string s)
{
int l=0,r=a.length();
int ans=0;
while(l<=r)
{
int mid=(l+r)/2;
if(a.compare(sa[mid],s.length(),s)<=0)
{
ans = mid;
l = mid+1;
}
else
{
r = mid-1;
}
}
return a.compare(sa[ans],s.length(),s)==0;
}