ในปัญหานี้ เราได้รับสตริงอินพุตและอาร์เรย์ arr[] งานของเราคือค้นหาการเกิดขึ้นของคำทั้งหมดในอาร์เรย์ในสตริง สำหรับสิ่งนี้ เราจะใช้อัลกอริทึม Aho-Corasick สำหรับการค้นหารูปแบบ
การค้นหาสตริงและรูปแบบเป็นสิ่งสำคัญในการเขียนโปรแกรม และในการเขียนโปรแกรม ยิ่งอัลกอริธึมดีเท่าไหร่ก็ยิ่งใช้งานได้จริงมากขึ้นเท่านั้น อัลกอริธึม Aho-Corasick เป็น อัลกอริธึมที่สำคัญและทรงพลังที่ทำให้การค้นหาสตริงเป็นเรื่องง่าย . เป็นชนิดของอัลกอริธึมการจับคู่พจนานุกรมที่จับคู่สตริงทั้งหมดพร้อมกัน อัลกอริทึมใช้ ทดลองโครงสร้างข้อมูล เพื่อนำไปปฏิบัติ
ทดลองโครงสร้างข้อมูล
Trie เป็น ทรีคำนำหน้าหรือแผนผังการค้นหาดิจิทัล โดยที่แต่ละขอบจะมีตัวอักษรบางตัวกำกับไว้ (แต่ละขอบขาออกจะมีตัวอักษรต่างกัน) .
มาดูตัวอย่างเพื่อทำความเข้าใจ Aho-Corasick อัลกอริทึม
ป้อนข้อมูล
string = "bheythisghisanexample"
arr[] = {"hey", "this", "is", "an", “example”} ผลผลิต
Word hey starts from 2 Word this starts from 5 Word is starts from 11 Word an starts from 13 Word example starts from 15
ความซับซ้อนของเวลาของอัลกอริทึมนี้คือ O(N+L+Z) โดยที่ N=ความยาวของอินพุตของสตริง/ข้อความ
L=ความยาวของคำหลัก (คำในอาร์เรย์)
Z=จำนวนการแข่งขัน
การนำไปใช้
อัลกอริทึม Aho-Corasick สามารถสร้างได้ด้วยขั้นตอนง่ายๆ เหล่านี้
-
สร้าง Trie โดยใช้ Queue เพื่อให้เราสามารถแสดงแต่ละตัวละครในคิวเป็นโหนด od 'trie'
-
สร้างลิงก์ล้มเหลว (ลิงก์ต่อท้าย) เป็นอาร์เรย์ที่สามารถเก็บอักขระตัวถัดไปและตัวปัจจุบันได้
-
สร้างลิงก์เอาต์พุตเป็นอาร์เรย์เพื่อเก็บคำที่ตรงกัน
-
สร้างฟังก์ชัน Traverse (FindNextState) เพื่อตรวจสอบอักขระทั้งหมด
ลิงก์ล้มเหลว (ลิงก์ต่อท้าย) − เมื่อเราไปถึงส่วนใดส่วนหนึ่งของสตริงที่เราไม่สามารถอ่านอักขระต่อไปได้ เราจะถอยกลับโดยทำตามลิงก์ต่อท้ายเพื่อพยายามรักษาบริบทให้มากที่สุด โดยสังเขป จะเก็บขอบทั้งหมดที่ตามมาเมื่ออักขระปัจจุบันไม่มีขอบใน Trie
ลิงค์เอาท์พุท − มันชี้ไปที่โหนดที่สอดคล้องกับคำที่ยาวที่สุดที่อยู่ในสถานะปัจจุบันเสมอ เรามั่นใจว่าเราจะเชื่อมโยงรูปแบบทั้งหมดเข้าด้วยกันโดยใช้ลิงก์เอาต์พุต
ตัวอย่าง
#include<iostream>
#include <string.h>
#include<algorithm>
#include<queue>
using namespace std;
const int MaxStates = 6 * 50 + 10;
const int MaxChars = 26;
int OccurenceOfWords[MaxStates];
int FF[MaxStates];
int GotoFunction[MaxStates][MaxChars];
int BuildMatchingMachine(const vector<string> &words, char lowestChar = 'a', char highestChar = 'z'){
memset(OccurenceOfWords, 0, sizeof OccurenceOfWords);
memset(FF, -1, sizeof FF);
memset(GotoFunction, -1, sizeof GotoFunction);
int states = 1;
for (int i = 0; i < words.size(); ++i){
const string &keyword = words[i];
int currentState = 0;
for (int j = 0; j < keyword.size(); ++j){
int c = keyword[j] - lowestChar;
if (GotoFunction[currentState][c] == -1){
GotoFunction[currentState][c] = states++;
}
currentState = GotoFunction[currentState][c];
}
OccurenceOfWords[currentState] |= (1 << i);
}
for (int c = 0; c < MaxChars; ++c){
if (GotoFunction[0][c] == -1){
GotoFunction[0][c] = 0;
}
}
queue<int> q;
for (int c = 0; c <= highestChar - lowestChar; ++c){
if (GotoFunction[0][c] != -1 && GotoFunction[0][c] != 0){
FF[GotoFunction[0][c]] = 0;
q.push(GotoFunction[0][c]);
}
}
while (q.size()){
int state = q.front();
q.pop();
for (int c = 0; c <= highestChar - lowestChar; ++c){
if (GotoFunction[state][c] != -1){
int failure = FF[state];
while (GotoFunction[failure][c] == -1){
failure = FF[failure];
}
failure = GotoFunction[failure][c];
FF[GotoFunction[state][c]] = failure;
OccurenceOfWords[GotoFunction[state][c]] |= OccurenceOfWords[failure];
q.push(GotoFunction[state][c]);
}
}
}
return states;
}
int FindNextState(int currentState, char nextInput, char lowestChar = 'a'){
int answer = currentState;
int c = nextInput - lowestChar;
while (GotoFunction[answer][c] == -1){
answer = FF[answer];
}
return GotoFunction[answer][c];
}
vector<int> FindWordCount(string str, vector<string> keywords, char lowestChar = 'a', char highestChar = 'z') {
BuildMatchingMachine(keywords, lowestChar, highestChar);
int currentState = 0;
vector<int> retVal;
for (int i = 0; i < str.size(); ++i){
currentState = FindNextState(currentState, str[i], lowestChar);
if (OccurenceOfWords[currentState] == 0)
continue;
for (int j = 0; j < keywords.size(); ++j){
if (OccurenceOfWords[currentState] & (1 << j)){
retVal.insert(retVal.begin(), i - keywords[j].size() + 1);
}
}
}
return retVal;
}
int main(){
vector<string> keywords;
keywords.push_back("All");
keywords.push_back("she");
keywords.push_back("is");
string str = "Allisheall";
cout<<"The occurrences of all words in the string ' "<<str<<" ' are \n";
vector<int> states = FindWordCount(str, keywords);
for(int i=0; i < keywords.size(); i++){
cout<<"Word "<<keywords.at(i)<<' ';
cout<<"starts at "<<states.at(i)+1<<' ';
cout<<"And ends at "<<states.at(i)+keywords.at(i).size()+1<<endl;
}
} ผลลัพธ์
The occurrences of all words in the string ' Allisheall ' are Word All starts at 5 And ends at 8 Word she starts at 4 And ends at 7 Word is starts at 1 And ends at 3