1. 程式人生 > >合併序列&&kmp演算法的初見與實現

合併序列&&kmp演算法的初見與實現

這題有一個很巧妙的方法,使用find函式 這裡就淺談一下find函式的用法:
1.find()

查詢第一次出現的目標字串:
a.find(b)就是從a中尋找b子串,如果找到的話就返回第一次找到他的下標,如果沒找到的話就返回一個
負數值 舉個例子:

#include<bits/stdc++.h>
using namespace std;
int main() {
  ios::sync_with_stdio(false);
  cin.tie(false);
  cout.tie(false);
  string a,b;
  a="1234567";
  b="4567"
; int c=a.find(b); cout<<c; string d="13"; int e=a.find(d); cout<<e; }

例子中的c的返回值是3 因為在a中找到了子串b,並且它的下標是3(預設下標從0開始尋找)
而e=a.find(d)的返回值是一個-1,因為他沒有在a中找到d
還有一個作用,那就是查詢從指定位置開始的第一次出現的目標字串:
什麼意思呢?就是從你指定的某一項開始尋找子串,如果找到的話就返回它的下標,注意這裡
返回的是下標,不是從某一項開始找的那個標誌數 比如:

#include<bits/stdc++.h>
using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(false); cout.tie(false); string a,b; a="1234567"; b="4567"; int c=a.find(b,2); cout<<c; string d="13"; int e=a.find(d); cout<<e; }

對上面的程式碼進進行修改以後c的返回值仍然是3而不是1

2.find_first_of()

查詢子串中的某個字元最先出現的位置。find_first_of()不是全匹配,而find()是全匹配

#include<bits/stdc++.h>
using namespace std;
int main() {
  ios::sync_with_stdio(false);
  cin.tie(false);
  cout.tie(false);
  string a,b;
  a="1234567";
  b="287";
  int c=a.find_first_of(b);
  cout<<c;
  string d="13";
  int e=a.find_first_of(d);
  cout<<e;
}

把上面的函式全部修改成find_first_of函式以後,將上面的引數改成287 就算不匹配也能返回第一項的位置
如果想跳過前幾個字元直接從後面找的話,還可以在find_first_of函式加一個數字引數,這就和上面的find
函式一樣了:不過這時候函式的返回值一個是6一個是0;

#include<bits/stdc++.h>
using namespace std;
int main() {
  ios::sync_with_stdio(false);
  cin.tie(false);
  cout.tie(false);
  string a,b;
  a="1234567";
  b="287";
  int c=a.find_first_of(b,4);
  cout<<c;
  string d="13";
  int e=a.find_first_of(d);
  cout<<e;
}

3.find_last_of()

這個函式與find_first_of()功能差不多,只不過find_first_of()是從字串的前面往後面搜尋,而find_last_of()是從字串的後面往前面搜尋。返回值還是下標,不過必須得全部匹配以後返回最後一位匹配的下標

#include<bits/stdc++.h>
using namespace std;
int main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  string a,b;
  a="1234567";
  b="34";
  int c=a.find_last_of(b);
  cout<<c;
}

拿這個舉個例子把,這樣寫的話因為第四位,即下標是3的時候才能完全匹配,所以返回的是3
如果要把4刪去,返回的就是2,因為直接匹配了 然後就返回

4.rfind()函式
這個函式可以從a字串的最後開始找子串,返回正序最後一次匹配的地方 eg:

#include<bits/stdc++.h>
using namespace std;
int main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  string a,b;
  a="341234567";
  b="34";
  int c=a.rfind(b);
  cout<<c;
}

此時在a中出現了兩次b,但是最後一次出現的下標是4,所以返回4而不返回0,挺有用的

5.find_first_not_of()

找到第一個不與子串匹配的位置
舉例子:

#include<bits/stdc++.h>
using namespace std;
int main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  string a,b;
  a="341234567";
  b="345";
  int c=a.find_first_not_of(b);
  cout<<c;
}

a是341234567 b是345 很顯然前兩項都是匹配的,所以返回的是第三項的下標,即2;

迴歸正題:

2651: 單詞

題目描述

有N個單詞和字串T,按字典序輸出以字串T為字首的所有單詞。

輸入

第一行包含一個整數N;接下來N行,每行一個單詞,長度不超過20。最後一行為字串T。

輸出

按字典序升序輸出答案。

樣例輸入
複製樣例資料 6
na
no
ki
ki
ka
ku
k

樣例輸出
ka
ki
ki
ku

提示

對於60%的資料,滿足1≤N≤1000;
對於100%的資料,滿足1≤N≤10000且所有字元均為小寫字母。

這題我嘗試用傳統方法做,開兩個string陣列,雖然string的特性是可以按字典序排序,但是發現我那樣做只能找到第一位匹配的,如果多了就沒辦法尋找了,程式碼如下:

#include<bits/stdc++.h>
using namespace std;
int main() {
  int n;
  cin>>n;
  char c;
  string a[2000];
  string b[2000];
  for(int i=0;i<n;i++)
  cin>>a[i];
  cin>>c;
  int k=0;
  for(int i=0;i<n;i++) {
    if(a[i][0]==c) {
      b[k]=a[i];
      k++;
    }
  }
  sort(b,b+k);
  for(int i=0;i<k;i++)
  cout<<b[i]<<endl;
}

這個樣例雖然過了,但是我只判斷了第一項,其實用這個方法仔細一想也可以,每一次遇到匹配的就加一,然後兩個for迴圈套一下,每次完全匹配就放到另一個string陣列中,然後排序輸出也是可以的哦 但是那也太麻煩了,提供給大家一組洛谷的輸入輸出樣例就知道有多麻煩了:

輸入:

100
wisfw
rb
zxitqbq
ptccakmjjoh
teremcxkcuadsjnkcd
wxqlgmlqeetl
hdbsegfs
tvknnru
qqzaxeiwfrkwggkbbqi
of
fncowmfsevqu
jkvjnzueo
eewtgocwkhetu
udaasgkwrljutkhhj
ptccmsm
fsdlpaeh
jwbjt
wswb
rq
ptcckxivrzjsoxcdcgixllxj
lsfweufkbscvp
bvuyxkovinjzyajrl
nxbvj
lgunb
zhmgwogx
ptcccev
niyjeqwmfa
tuombvgeloyb
rjubdwksvss
ptccmjnh
dkvcihklrj
xecpvqbtxbdyyuzk
sxoklnzebdzoucerlo
ulrmojhpfoadi
ptccpvt
kfozrnaunjczy
ptcckeeyrjyvwbsljpe
ptccunxgczxtxelam
kfphtzlkcu
ewgwaf
psqevzric
tpe
musf
hhxezht
xxsvwybigolsbpvmfz
ptccfh
nvfjzfftnjm
xcnlkbzpsuvav
muwfqcdipohjhmyxqkzx
yvvnuoyvrw
ptccb
zkwqzkfzjooqppbluewe
ptcclt
ptccbaqzeytgpnqkscreoh
votcxsogpopkjyv
ptccqbmo
ptccqitcpupnzvgvnynw
tqzhcwewxyhemlh
tsgb
ptccrdyfvhpiz
dqxjimytgh
ptcczrn
efuzryakahlqyymtadl
ptccdkguhrbldphmjqnx
bcecssfvtzwxgufl
dypcvvx
ptccfxpqxtogr
ptccgnmzzccskdgzlknckpsl
qfcvkd
v
taapyfojsiaxr
ptccmmbmrxybinsvhtwdmdo
gopj
bxursvhqckh
ymsokijioarxxwkfimwv
ptccqiymyadvofprnl
ptccivakendfjlmx
ptccswydhxayxqdtnelnbw
aimk
ptccndfpmsbgijgbzz
ptcckpbmxyzx
cfhjkoezzfuouosjzv
tofrmkungwfpchjpyfk
dbhxfeniy
uanhmsqhpwiifrmrcfcu
maznpifjqokmoay
itrr
tgqnkjd
fmexumzcamofem
inxarkcqmosppvl
bpzlmn
k
xjzkdvnzyybyu
ro
uchfbagqi
ptccjvrziqjojneqyhz
zpiouboncchqrcvakwnh
hxgszx
rltpqixvykdlbzqo
kmshsfjjtpcjam
ptcc

輸出:

ptccakmjjoh
ptccb
ptccbaqzeytgpnqkscreoh
ptcccev
ptccdkguhrbldphmjqnx
ptccfh
ptccfxpqxtogr
ptccgnmzzccskdgzlknckpsl
ptccivakendfjlmx
ptccjvrziqjojneqyhz
ptcckeeyrjyvwbsljpe
ptcckpbmxyzx
ptcckxivrzjsoxcdcgixllxj
ptcclt
ptccmjnh
ptccmmbmrxybinsvhtwdmdo
ptccmsm
ptccndfpmsbgijgbzz
ptccpvt
ptccqbmo
ptccqitcpupnzvgvnynw
ptccqiymyadvofprnl
ptccrdyfvhpiz
ptccswydhxayxqdtnelnbw
ptccunxgczxtxelam
ptcczrn

就算能做,也太麻煩了,所以我選擇find函式,如果返回值是0的話就可以放到數組裡面,然後很方便的排序輸出了!!! 程式碼如下:

#include<bits/stdc++.h>
using namespace std;
int main() {
  string a[20000];
  string b;
  int n;
  cin>>n;
  for(int i=0;i<n;i++)
    cin>>a[i];
  cin>>b;
  sort(a,a+n);
  for(int i=0;i<n;i++) {	
    if(a[i].find(b)==0)
    cout<<a[i]<<endl;
  }
}

總結:在資料小的時候感覺find函式都能替代kmp演算法,但是資料量一大肯定廢了,雖然這兩種的實現都是線性的,但是要是做那種重複字串的題目,用find函式必須要在for外面套一個while 這樣就變成了n^2的級別了,還是得用kmp啊 正好昨天在機房聽完馬大佬的講課,聽懂了kmp演算法 先把自己打的程式碼貼上,之後再詳細的說一下思考過程吧!

先說一下kmp的實現包括兩個過程,第一個是自己匹配自己,找一下next陣列,如果有大於0的next[i]出現就說明子串中有重複的部分,這時候kmp演算法的優勢就顯現出來了:太快了!!!、
先貼程式碼,之後再詳細說明:

#include<bits/stdc++.h>
using namespace std;
char a[100010];
char b[100010];
int next[100010];
int main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  cin>>a+1>>b+1;
  int la=strlen(a+1);
  int lb=strlen(b+1);
  int j=0;
  for(int i=2;i<=lb;i++) {
    while(j&&b[i]!=b[j+1])
    j=next[j];
    if(b[i]==b[j+1])
    j++;
    next[i]=j;
  }
  j=0;
  for(int i=1;i<=la;i++) {
    while(j&&a[i]!=b[j+1])
    j=next[j];
    if(a[i]==b[j+1])
    j++;
    if(j==lb
    ) {
      cout<<i-j+1<<endl;
      j=next[j];
    }
  }
  for(int i=1;i<=lb;i++)
  cout<<next[i]<<" ";
}

這篇部落格近期就會更新,也許就是今晚哦~ 敬請期待