1. 程式人生 > >刪除子串——KMP

刪除子串——KMP

題目描述:
題目來源: USACO 2015 February Contest,Silver——Problem 1
Censoring
給定一個字母串 S 和一個字母串 T ,所有字母都由小寫字母 a..z 構成,S 和 T 的長度均不超過 1,000,000 ,T 的長度不會超過 S 。
從左往右列舉 S 串的每個字元,當列舉的一段連續字串為 T ,則在 S 串中刪掉這段連續字串 T,後續字元依次向左移動填充刪除的位置。然後在 S 中繼續往右列舉,直到 S 串全部列舉完成為止。
請你輸出最後的 S 串。
輸入格式:
輸入的第一行是字串 S ,第二行是字串 T 。
輸出格式:
輸出最後的 S 串。資料保證 S 串不會為空串。
樣例輸入:


whatthemomooofun
moo
樣例輸出:
whatthefun
樣例說明
當列舉到 whatthemomoo 時,刪除 moo ,得到 whatthemo ;
繼續列舉 o ,得到 whatthemoo ,再次刪除 moo ,得到 whatthe ;
繼續列舉 fun ,最後得到 whatthefun 。
題目分析:
KMP。這道題的難點在於刪掉一個T後,前後又可能出現一新的T串,並且怎樣”刪”也是一個問題,怎樣才不會超時。最開始我把刪掉的部分賦成0,超時;把後面的往前移,超時。最後的方法是匹配的同時依次存入一個數組,每次刪掉一個T時,此陣列下標就減掉一個T的長度,相當於刪掉了T,然後繼續存。對於合併後可能產生新的T的問題,處理見程式碼。
附程式碼:

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cctype>
#include<queue>
#include<iomanip>
#include<set>
#include<map>
#include<cmath>
#include<algorithm>
using
namespace std; const int maxn=1e6+10; int lens,lent,nxt[maxn],tot,pre[maxn]; char s[maxn],t[maxn],a[maxn]; int main() { //freopen("lx.in","r",stdin); scanf("%s%s",s+1,t+1); lens=strlen(s+1);lent=strlen(t+1); for(int i=2,j=0;i<=lent;i++) { while(j!=0&&t[i]!=t[j+1]) j=nxt[j]; if(t[i]==t[j+1]) j++; nxt[i]=j; } for(int i=1,j=0;i<=lens;i++) { while(j!=0&&s[i]!=t[j+1]) j=nxt[j]; if(s[i]==t[j+1]) j++; a[++tot]=s[i]; pre[tot]=j;//記錄每一個位置的j if(j==lent) { tot-=lent;//相當於a中刪除了一個t字串 j=pre[tot];//將刪掉的t字串的前一個位置的j付給現在,相當於跨過了t匹配,處理了合併後可能產生新的t的問題 } } for(int i=1;i<=tot;i++) cout<<a[i]; return 0; }