2013-05-03
Z algorithmで文字列探索を試す
はじめに
名前がかっこいい。
codeforcesにある解説を試してみる。
Z algorithmとは
- 文字列Sと部分文字列S[i..]の最長共通接頭辞数をZ[i]とし、すべてのiについて、それをO(n)で求めるアルゴリズム
- 単純な方法だとO(n^2)
- 1996,97年あたりにGusfieldによって提案された
アルゴリズム
うまく過去の情報をメモしておいて計算量を減らす。
- iのZ-boxを範囲[i, i+Z[i]-1]と定義する
- あるiについて、i以下のjについてZ-boxを考え、
- Z-boxの終点で最も右側にあるものをr_i、そのr_iのペアとなるZ-boxの始点をl_iとする
- Z[k]を求めるときは、過去のZとr_{k-1}とl_{k-1}があれば求められる
- k>rの場合
- rを超えてるので、新しくkでのZ-boxを考える必要があるので、部分文字列S[k..]の接頭辞を比較する
- k=l, r=k+Z[k]-1とする
- k<=rの場合
Z algorithmを使った文字列探索
文字列Tからパターン文字列Pを探索するために、この2つを連結したP$Tという文字列を作る。
この文字列について、Tの部分のZ[i]を全て求め、Z[i]=|P|となるものを列挙すれば探索できる。
コード
codeforcesのを参考に。
#include <iostream> #include <algorithm> #include <string> #include <vector> //naive : O(n^2) int findLCP(const std::string& s){ int ret = 0; int n = s.length(); std::vector<int> z(n, 0); for(int i=1; i<n; i++){ for(int j=0; i+j<n; j++){ if(s[j] == s[i+j]) z[i]++; else break; } ret = std::max(ret, z[i]); } return ret; } //Z algorithm : O(n) int Zalgorithm(const std::string& s){ int ret = 0; int n = s.length(); std::vector<int> z(n, 0); int L = 0, R = 0; for(int i=1; i<n; i++){ if(i>R){ L = R = i; while(R<n && s[R-L] == s[R]) R++; z[i] = R-L; R--; }else{ int k = i-L; if(z[k] < R-i+1){ z[i] = z[k]; }else{ L = i; while(R<n && s[R-L] == s[R]) R++; z[i] = R-L; R--; } } ret = std::max(ret, z[i]); } return ret; } //exact search by Z algorithm std::vector<int> Zsearch(const std::string& T, const std::string& P){ std::string S = P + "$" + T; std::vector<int> z(S.length(), 0); int L = 0, R = 0; for(int i=1; i<S.length(); i++){ if(i>R){ L = R = i; while(R<S.length() && S[R-L] == S[R]) R++; z[i] = R-L; R--; }else{ int k = i-L; if(z[k] < R-i+1){ z[i] = z[k]; }else{ L = i; while(R<S.length() && S[R-L] == S[R]) R++; z[i] = R-L; R--; } } } std::vector<int> ret; for(int i=P.length()+1; i<S.length(); i++){ if(z[i] == P.length()){ ret.push_back( i-(P.length()+1) ); } } return ret; } int main(){ std::string str = "aabadaabcaaba"; //最長共通接頭辞の長さを返す std::cout << findLCP(str) << std::endl; std::cout << Zalgorithm(str) << std::endl; std::cout << "----" << std::endl; //文字列strからパターン文字列patをすべて探す std::string pat = "aab"; std::vector<int> ret = Zsearch(str, pat); for(int i=0; i<ret.size(); i++){ std::cout << ret[i] << std::endl; } return 0; }
結果
$ ./a.out 4 4 ---- 0 5 9
できてるっぽい。
現実的には、検索するならより高速に検索できるKMP法やBM法。
文字列の最長接頭辞(接尾辞)を求められるので、そちらを使った応用がメインっぽいです。(上記のアルゴリズムのpre-processingとして利用、など)
参考
- http://codeforces.com/blog/entry/3107
- http://www.eui.upm.es/~fmartin/webpgomez/Docencia/Pattern-Recognition/PR-Notes-Chapter-4.pdf
- http://www.cs.uku.fi/~kilpelai/BSA05/lectures/slides02.pdf
- http://d.hatena.ne.jp/deve68/20120201/1328109890
- http://www.cs.umd.edu/class/fall2011/cmsc858s/Lec02-zalg.pdf
- http://www-imai.is.s.u-tokyo.ac.jp/seminar/reading/resume/02winter_01-02.pdf
トラックバック - http://d.hatena.ne.jp/jetbead/20130503/1367517589
リンク元
- 100 https://www.google.co.jp/
- 21 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CC4QFjAA&url=http://d.hatena.ne.jp/jetbead/20110904/1315147129&ei=_TeGUa2oFomxkAXf6YG4BA&usg=AFQjCNHXcgooileeg7G8VC5CJdZf8pCICw&sig2=Ua0CRehufhwUo9uKS-PJ8Q&bvm=bv.45960087,d
- 10 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=3&ved=0CDkQFjAC&url=http://d.hatena.ne.jp/jetbead/20110723/1311414222&ei=vWeDUc6GNsyFlAWHj4HgCA&usg=AFQjCNEp6iPm_D8UjS9-q5hWF-o6m0xHdQ
- 8 http://gunosy.com/
- 8 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=2&ved=0CEUQFjAB&url=http://d.hatena.ne.jp/jetbead/20110802/1312298173&ei=51yDUfqbEofkkgXFg4GQDQ&usg=AFQjCNHME2ueEaIJqxHhCsVYCIqBY27aVQ&sig2=1mZLCRE3Rpv20viR1gKG-w&bvm=bv.45960087,d
- 8 https://www.google.com/
- 7 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&frm=1&source=web&cd=11&ved=0CHAQFjAK&url=http://d.hatena.ne.jp/jetbead/20110808/1312820433&ei=492FUcKrI47QlAW31YCgBw&usg=AFQjCNHzKPq-x3epztT5uVKXz63bu_CsIQ&sig2=HDKSnEnPfGRVyo7Ecr6opw
- 7 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=4&ved=0CFQQFjAD&url=http://d.hatena.ne.jp/jetbead/20130328/1364403521&ei=ZM2EUfjtAofLkgXqqYGAAg&usg=AFQjCNH2RXGhzejp_nZo9ScwZurnbET2-w&sig2=AHXDDx0MnT21FM7h-uDoDg&bvm=bv.45960087,d
- 6 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=7&ved=0CFcQFjAG&url=http://d.hatena.ne.jp/jetbead/20120930/1349014672&ei=wGOJUbLYIY29kQW_xoD4DA&usg=AFQjCNFjC5CHkLZMdx-5PCY8M4SMsGtl-Q&sig2=z1lT0ipL3wFXPOHjQxWvjQ&bvm=bv.46226182,d
- 4 http://b.hatena.ne.jp/hiroyuki1983/アルゴリズム/