SCU4438 Censor(审查员) (KMP算法与模拟栈的应用 || HASH表与模拟栈的结合)

 

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.

弗雷格现在是一个编辑员,专门审查所谓的河蟹词。

他现在有一个长文本p,他的工作相对简单点——就是去找到敏感词的首次出现的位置并且删掉它。

弗雷格一遍又一遍的重复,帮助他去完成这个无聊的任务。

Input

The input consists of multiple tests. For each test:

输入包含多组数据,对于每组数据:

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

第一行包含一个字符串W,第二行包含一个字符串P

(1≤length of w,p≤5⋅1061≤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

  当我刚看到这个题的时候,因为想到删除文本后后边的文本要跟着前移至删除文本的位置,类似于Python的动态内存管理。我一开始的想法是kmp+vector,不过在SCUOJ上得到了1986ms的高评价,只好作罢。

  Caution:由于本题数据不小,所以慎用string类型和cin,cout,stl-stack(纯C时间200~400ms,C with STL and iostream 时间1000~1400ms,时间限制1500ms)

KMP+模拟栈

   由于在程序实现中我们需要中断文本,由此达成删去关键词的目的,栈这种数据结构刚好能满足我们的要求。我们在用kmp算法匹配相应字符串的同时把原先的文本字符串逐渐压入栈中,如果匹配到了,那么就把匹配到的字符串整个从栈中拽出,实现了“删除”的效果,而匹配是在被匹配成功字符串的最后一个字符后继续进行的,所以这个过程也就满足了“自动连接”的效果。

简述思路

  1. 首先我们必须把KMP算法运行所必须的NEXT数组通过某个单独的模块“生产”完成,这个过程本质上就是KEYWORD字符串对自己的匹配(match),而NEXT数组的作用既是在某次匹配失败后KEYWORD所属指针要回退到字符串的哪个位置。
  2. 通过一个循环逐一把TEXT字符串的字符压入栈中,然后对栈中所有字符执行KMP算法,若成功匹配,则把这个子字符串从栈中驱逐(把模拟指针减去子字符串长度)。
  3. 栈中剩下的字符就是答案。

详情见代码

#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#define lldin(a) scanf("%lld",&a)
#define din(a) scanf("%d",&a)
#define printlnlld(a) printf("%lld\n",a)
#define printlnd(a) printf("%d\n",a)
#define printlld(a) printf("%lld",a)
#define printd(a) printf("%d",a)
#define reset(a,b) memset(a,b,sizeof(a))
const int INF=0x3f3f3f3f;
using namespace std;
const double PI=acos(-1);
typedef long long ll;
typedef long double ld;
const int mod=1000000007;
///Schlacht von Stalingrad
/**Although there will be many obstructs ahead,
the desire for victory still fills you with determination..**/
char text[7650000],key[7650000];
int next2[7650000],tmp[7650000];
ll indice;//仿真栈的指针
char impersonated[7650000];//仿真栈
void generator()//next数组生成函数,这个数组是用来决定某次匹配失败后指向
匹配文本(相对于被匹配文本而言)的指针回到前面的哪个位置。     
{
    ll ph=-1,pt=0;
    next2[0]=-1;
    ll klen=strlen(key);
    while(pt<klen)
    {
        if(ph==-1||key[ph]==key[pt])//我 匹 配 我 自 己
        {
            ph++,pt++;
            next2[pt]=ph;
        }
        else
            ph=next2[ph];//跳回去
    }
}
void assult()
{
    generator();
    ll tlen=strlen(text),klen=strlen(key);
    ll pk=0;
    indice=0;
    for(int pt=0; pt<tlen; pt++)//for循环表示指向原文本的指针
    {
        impersonated[indice++]=text[pt];//把这个字符压入栈中
        while(pk>0&&key[pk]!=text[pt])
            pk=next2[pk];//指针跳回去
        if(key[pk]==text[pt])
            pk++;//前移
        tmp[indice]=pk;//因为栈中逐渐形成了一个字符串,所以需要把next数组移植过来.
       // cout<<indice<<" "<<pk<<endl;
        if(pk==klen)
        {
            indice-=klen;//逐出字符串
            pk=tmp[indice];//指针回跳
        }
    }
}
int DETERMINATION()
{
    while(~scanf("%s %s",key,text))
    {
        assult();
        impersonated[indice]='\0';//这个字符数组(仿真栈)的最后一个字符设定为空字符作为结束
        printf("%s\n",impersonated);
    }
    return 0;
}

HASH表+模拟栈

  我们都知道hash表是一种KEY-VALUE类数据结构,只要掌握一个键值,我们就可以访问这个键值指向的内容,相应的,如果键值错误,我们自然无法访问到正确的内容。

思路大致如下:

  1.   定义一个好用的HASH数用来“加密”你的字符串
  2.   求出KEYWORD的HASH值
  3.  通过循环把TEXT的字符压入模拟栈中,并求出栈内KEYWORD长度的(长度即KETWORD.SIZE())的hash值,通过这样的公式:STACK[CURRENT_LOCATION]-(STACK[CURRENT_LOCATION-KEYWORD.SIZE()]*HASH_FACTORIAL[KEYWORD.SIZE())
  4. 判断求得的HASH值是否等于KEYWORD的HASH值,如果是,则把栈指针下移(删去这段字符串)。 
  5. 输出栈中从栈底到指针处的元素

代码如下:

#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#define lldin(a) scanf("%lld",&a)
#define din(a) scanf("%d",&a)
#define printlnlld(a) printf("%lld\n",a)
#define printlnd(a) printf("%d\n",a)
#define printlld(a) printf("%lld",a)
#define printd(a) printf("%d",a)
#define reset(a,b) memset(a,b,sizeof(a))
const int INF=0x3f3f3f3f;
using namespace std;
const double PI=acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod=1000000007;
const int tool_const=1999112620000907;
const int tool_const2=33;
///Schlacht von Stalingrad
/**Although there will be many obstructs ahead,
the desire for victory still fills you with determination..**/
char text[6000000],keyword[6000000];
ull hash_array[6000000],hash_of_text[5050000];
char forging_stack[5050000];
void readiness()
/*这个数组实际上就是HASH数值的幂,因为judge函数里我们会对两个HASH值作差,
由于我们想求正儿八经的关键词HASH值,所以必须要在减数那里乘上相应的HASH值的幂来平衡。
*/
{
    hash_array[0]=1;
    for(int i=1;i<=500007;i++)
        hash_array[i]=hash_array[i-1]*tool_const2;
}
bool judge(ll current,ll klen,ll hashvalue)
{
    if(hash_of_text[current]-hash_of_text[current-klen]*hash_array[klen]==hashvalue)
         return true;
    else
        return false;
}
int DETERMINATION()
{
    readiness();
    while(~scanf("%s %s",keyword,text))
    {
        ull klen=strlen(keyword);
        ull tlen=strlen(text);
        ull khash=0;
        for(int i=0;i<klen;i++)//关键词的HASH值
          khash=khash*tool_const2+(keyword[i]-'a'+1);
        ll top_pointer=0;
        hash_of_text[0]=0;
        for(int i=0;i<tlen;i++)
        {
            forging_stack[top_pointer++]=text[i];
            hash_of_text[top_pointer]=hash_of_text[top_pointer-1]*tool_const2+(text[i]-'a'+1);
            if(top_pointer>=klen&&judge(top_pointer,klen,khash))
                {
                    //cout<<forging_stack<<endl;
                    top_pointer-=klen;
                    //cout<<forging_stack<<endl;
                }

        }
        for(int i=0;i<top_pointer;i++)
            printf("%c",forging_stack[i]);
        printf("\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43874261/article/details/89483921