思路:
经典字典树
flag[i]代表第i个节点是否某为一个字符串的终点。
child[N][2]代表字典树,存储每一个节点的rank,child[i][0]==-1代表第i个节点的左子树为空,
对于每一个字符串,对每一个字符进行处理。
这是向字典树中插入字符的函数,即代码的精华部分。
int insert(string str){
int crt=root;
bool judge=0;
int len=str.size();
for(int i=0;i<len;i++){
int x=str[i]-'0';
if(child[crt][x]==-1){//遇到空值
child[crt][x]=++tot;
flag[tot]=0;
}else{
//在当前节点已被占用的情况下:
//str是其他字符串的前缀||其他字符串是str的前缀
if(i==len-1||flag[child[crt][x]])
judge=1;
}
crt=child[crt][x];
}
flag[crt]=1;
return judge;
}
完整代码:
#include<string.h>
#include<iostream>
#include<string>
using namespace std;
const int N=1010;
struct trie{
int tot;
int root;
int child[N][2];
int flag[N];
trie(){
memset(child,-1,sizeof(child));
tot=0;
root=0;
}
void clear(){
memset(child,-1,sizeof(child));
tot=0;
root=0;
}
int insert(string str){
int crt=root;
bool judge=0;
int len=str.size();
for(int i=0;i<len;i++){
int x=str[i]-'0';
if(child[crt][x]==-1){//遇到空值
child[crt][x]=++tot;
flag[tot]=0;
}else{
//str是其他字符串的前缀||其他字符串是str的前缀
if(i==len-1||flag[child[crt][x]])
judge=1;
}
crt=child[crt][x];
}
flag[crt]=1;
return judge;
}
};
int main(){
string ss;
trie tri;
int cas=1;
bool judge=false;
while(cin>>ss){
if(ss!="9"){
if(tri.insert(ss))
judge=true;
}
else{
if(!judge)
cout<<"Set "<<cas<<" is immediately decodable"<<endl;
else
cout<<"Set "<<cas<<" is not immediately decodable"<<endl;
cas++;
judge=false;
tri.clear();
}
}
return 0;
}
KMP算法:
找了很多博客,都写的乱七八糟,没有注释的代码和胡乱画的图,搞得我在kmp算法上浪费了很多时间。直到看到了这篇:
传送门-对kmp算法解析并模拟的博客
这篇博客写得真的好,是我见过的写得最清楚明白的原创博客,吹爆~
当然了,看完了不一定理解的话,需要自己手动模拟一遍。
关键代码:
求最长相同前后缀长度以及匹配过程:
//不加注释能直接看懂这段的都是大神!
/*
get_f(string)
求字符串的最长相同前后缀长度
从位置1(第二个字符)开始遍历
如:字符串aa,f[1]=1;f存储的是最长相同前后缀中前缀最后一个字符的位置
看不懂的可以手动模拟一下
*/
void get_f(char *x){
//f数组需要都初始化为-1
for(int i=1;i<m;i++){//每一次遍历求0~i的最长相同前后缀的长度
int j=f[i-1];//初始化为0~i-1部分的最长相同前后缀长度的位置
while(x[j+1]!=x[i]&&j>=0){//j之前的部分就不用再匹配了
j=f[j];
}
if(x[j+1]==x[i]){
f[i]=j+1;
}
else{
f[i]=-1;
}
}
}
void kmp(char *a,char *b){
int i=0,j=0;
int ans=0;
while(i<n){
if(a[i]==b[j]){
i++;
j++;
if(j==m){
ans++;
j=f[j-1]+1;
//已经匹配上,从f[m]+1的位置开始匹配就行
//也就是从最长的相同前后缀+1的位置开始匹配
//因为前面的部分都是一样的,不用再匹配
}
}
else{
if(j==0){
i++;
}
else{
j=f[j-1]+1;
//中间没匹配上
}
}
//其实只要自己写个例子模拟一下,非常好理解,
//单看代码很难理解。
}
cout<<ans<<endl;
}
完整代码:
#include<iostream>
#include<cstring> //卡了STL,这个string用不得
#include<cstdio>
using namespace std;
//string p,s;
int T;
int f[10010];
char p[10010];
char s[1000010];
int m;
int n;
void
void get_f(char *x){
for(int i=1;i<m;i++){
int j=f[i-1];
while(x[j+1]!=x[i]&&j>=0){
j=f[j];
}
if(x[j+1]==x[i]){
f[i]=j+1;
}
else{
f[i]=-1;
}
}
}
void kmp(char *a,char *b){
int i=0,j=0;
int ans=0;
while(i<n){
if(a[i]==b[j]){
i++;
j++;
if(j==m){
ans++;
j=f[j-1]+1;
}
}
else{
if(j==0){
i++;
}
else{
j=f[j-1]+1;
}
}
}
cout<<ans<<endl;
}
int main(){
cin>>T;
while(T--){
memset(f,-1,sizeof(f));
cin>>p;
cin>>s;
m=strlen(p);
n=strlen(s);
get_f(p);
kmp(s,p);
}
return 0;
}