Censor

frog is now a editor to censor so-called sensitive words (敏感词).

She has a long text pp. Her job is relatively simple -- just to find the first occurence of sensitive word ww and remove it.

frog repeats over and over again. Help her do the tedious work.

Input

The input consists of multiple tests. For each test:

The first line contains 11 string ww. The second line contains 11 string pp.

(1length of w,p51061≤length of w,p≤5⋅106, w,pw,p consists of only lowercase letter)

Output

For each test, write 11 string which denotes the censored text.

Sample Input

    abc
    aaabcbc
    b
    bbb
    abc
    ab

Sample Output

    a
    
    ab


题意:给出两个字符串,在第二个里面去找寻有没有第一个,有的话删除,然后再合并字符串,问最后的字符串是怎样的
如样例一 aaabcbc -> aabc -> a

思路:我们想想,这么大的数据范围,光是我们查找子串是否存在就必须要用kmp,那我们再想想如何优化呢
怎么解决那个删除之后再合并呢,我开始想的是用数组模拟链表,那样删除操作的话,只要改变一个指向就可以了
列出下面我的错误代码
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
struct sss
{
    int next;
    char c;
}s1[5000001];
int len1,len2;
int head;
int next1[5000001];
char s2[5000001];
char str[5000001];
int num[5000001];
void getnext(char s[])
{
    int i=0,j=-1;
    next1[0]=-1;
    while(i<len2)
    {
        if(j==-1||s[i]==s[j])
        {
            next1[++i]=++j;
        }
        else j=next1[j];
    }
}
int kmp(struct sss s1[],char s2[])
{
    int i=head,j=0;
    int cnt=0;
    num[cnt++]=i;
    while(i<len1)
    {
        if(j==-1||s1[i].c==s2[j])
        {
            i=s1[i].next;
            num[cnt++]=i;
            j++;
            if(j==len2) 
            {
                if(cnt-len2-2<0) head=i; 
                else s1[num[cnt-len2-2]].next=i;
                return 1;
            }
        }
        else  j=next1[j];
    }
    return 0;
}
int main()
{
    while(scanf("%s",s2)!=EOF)
    {
        scanf("%s",str);
        len1=strlen(str);
        len2=strlen(s2); 
        if(len2>len1)
        {
            printf("%s\n",str);
            continue;
        } 
        for(int i=0;i<len1;i++)
        {
            s1[i].next=i+1;
            s1[i].c=str[i];
        }
        getnext(s2);
        head=0;
        while(kmp(s1,s2));
        int i=head;
        while(i<len1)
        {
            printf("%c",s1[i].c);
            i=s1[i].next;
        }
        printf("\n");
    }
}
View Code

但是我的想法是一旦删除之后,就改变指向,然后再次退出去,然后再从头开始找,这样无疑还是超时了

我们再想想怎么利用kmp的性质去优化,我在每个位置存下模式串当前匹配到哪个位置,

然后我用一个数组存下来,当`我找到一个之后,那个匹配之前的位置的模式位置值又赋值给当前即可

如    样例一

aaabcbc

01112323

abc

删除一遍后j的值并不是从0开始而是赋值abc之前的那个位置值1,代表以后匹配了a,无需再去比

 

字符串中我们需要灵活的利用kmp的思想来优化时间复杂度

具体看代码

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long LL ;
const int MX=5555555;
char s[MX],t[MX],ans[MX];
int  next1[MX],pos[MX],len1,len2;
 
void init() {
    memset(ans,0,sizeof(ans));
    memset(pos,0,sizeof(pos));
    memset(next1,0,sizeof(next1));
}
 
struct Node {
    char ch;
    int j;
    Node() {};
    Node(char c,int n):ch(c),j(n) {};
};
 
void GetNext() {
    int i=0,j=-1;
    next1[0]=-1;
    while(i<len2) {
        if(j==-1||t[i]==t[j]) {
            i++;
            j++;
            if(t[i]==t[j]) {
                next1[i]=next1[j];
            } else next1[i]=j;
        } else j=next1[j];
    }
}
void KMP() {
    int i=0,j=0;
    int cnt=0;
    while(i<len1) {
        ans[cnt]=s[i++]; 
        while(!(j==-1||ans[cnt]==t[j])) {
            j=next1[j];
        }
        j++;
        cnt++; 
        pos[cnt]=j;//存当前模式串匹配到哪个位置
        if(j==len2) {
            cnt-=len2;//直接赋值之前的位置给他
            j=pos[cnt];
        }
    }
    for(int i=0; i<cnt; i++) {
        putchar(ans[i]);
    }
    puts("");
}
int main() {
    while(~scanf("%s %s",t,s)) {
        init();
        len1=strlen(s);
        len2=strlen(t);
        GetNext();
        KMP(); 
    }
    return 0;
}