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

    abcaaabcbcbbbbabcab

Sample Output

    aab

当我刚看到这个题的时候,因为想到删除文本后后边的文本要跟着前移至删除文本的位置,类似于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;}elseph=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;elsereturn 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;
}

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

  1. KMP算法详解:使用部分匹配表PMT来理解KMP算法,使用Java实现

    有些算法,适合从它产生的动机,如何设计与解决问题这样正向地去介绍.但KMP算法真的不适合这样去学.最好的办法是先搞清楚它所用的数据结构是什么,再搞清楚怎么用,最后为什么的问题就会有恍然大悟的感觉.我试 ...

  2. Java #JVM(HotSpot) 运行时数据区 #程序计数器(PC寄存器)#虚拟机栈(栈帧:局部变量表、操作数栈……)#堆……

    目录 JVM中线程的说明 程序计数器(PC寄存器) 虚拟机栈 · 栈帧 ·· 局部变量表 ·· 操作数栈 ·· 动态链接 ·· 方法返回地址 ·· 本地方法栈 堆 · 查看堆的大小 · 堆的默认大小 ...

  3. CSP-S模拟 环球巡演(hash表+贪心)

    传送门 把所有关键点提出来处理,然后分成相邻两个数分别贪心计算答案最后加起来. 现在把问题转化成了如下模型: 给你一个010101序列,你可以进行如下几种操作(四种操作代价不同): 删去一个1 删去一 ...

  4. 为什么说在KMP算法中文本串中的每个字符都是需要进行比较操作的?

     KMP算法需要计算一个shift或者next表,这个表是一个部分匹配表,通过这个next表来计算当字符不匹配的时候移动的位数,这个移动位数的计算公式为 移动位数 = 已匹配的字符数 - 对应的n ...

  5. 七分钟理解什么是 KMP 算法

    本文是介绍 什么是 BF算法.KMP算法.BM算法 三部曲之一. KMP算法 内部涉及到的数学原理与知识太多,本文只会对 KMP算法 的运行过程. 部分匹配表 .next数组 进行介绍,如果理解了这三 ...

  6. KMP算法 - - - 清晰易懂版

    KMP算法 KMP 算法是三位学者在 Brute-Force 算法的基础上同时提出的模式匹配的改进算法.Brute- Force算法在模式串中有多个字符和主串中的若干个连续字符比较都相等,但最后一个字 ...

  7. 【算法】 哈希表 自己模拟hashMap

    文章目录 1.概述 2.Hash表 3. 模拟 1.概述 视频地址:https://www.bilibili.com/video/BV1E4411H73v?p=86 哈希表(散列)-Google.上机 ...

  8. Censor KMP算法

    Censor frog is now a editor to censor so-called sensitive words (敏感词). She has a long text pp. Her j ...

  9. C - Censor KMP算法

    Censor frog is now a editor to censor so-called sensitive words (敏感词). She has a long text p. Her jo ...

最新文章

  1. 网站性能工具Yslow的使用方法
  2. Windows内核HAL相关学习
  3. [导入]DotNet软件开发框架
  4. 费曼学习法:为何被称为史上最牛的学习法,它的本质究竟是什么?
  5. win7系统安装信息服务器不可用怎么办,win7系统提示rpc服务器不可用怎么办
  6. C++设计模试之S状态模式
  7. 跳跃游戏—leetcode55
  8. 一张图片学Python
  9. Weblogic 节点启动
  10. python txt转json_实战篇 | 用Python来找你喜欢的妹子(二)
  11. Windows+Python3.7下自动生成requirements.txt文件
  12. tomcat热部署和热加载
  13. 矩阵快速幂 算法原理
  14. 基于web在线餐饮网站的设计与实现——蛋糕甜品店铺(HTML+CSS+JavaScript)
  15. cocos creator全局开关音效设置之静音开关
  16. es7之Reflect Metadata
  17. 提醒用户的方式 notification+Dialog
  18. excel入门/常用的技巧
  19. 电脑知识:电脑被黑客攻击,那么如何电脑判断沦为“肉鸡”?
  20. 触摸按键PCB设计要点

热门文章

  1. Raspberry Pi (树莓派) - 图形化界面启动和命令行界面启动
  2. 《小鸡快跑》的成功故事
  3. 【YOLOv5实战2】基于YOLOv5的交通标志识别系统-自定义数据集
  4. Sqlite数据库中索引的使用、索引的优缺点[转]
  5. 在canvas画布上多次绘制图形叠加的效果
  6. (9)Android之路====Android系统OTA更新
  7. java取余(java取余数的函数)
  8. [ZJOI2008]无序运动Movement
  9. 微信小程序小Demo
  10. Python,折线图,手写数字,图像反色、二值化、28X28