-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.cpp
More file actions
179 lines (147 loc) · 4.21 KB
/
main.cpp
File metadata and controls
179 lines (147 loc) · 4.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#include <iostream>
#include <queue>
using namespace std;
char desc[1000000];
char keyword[51];
class Node {
public:
bool m_isLeaf;
Node *nodes[26];
Node *falure;
char m_val;
int count;
public:
Node(char val='\0', bool leaf = false) {
m_val = val;
m_isLeaf = leaf;
falure = NULL;
count = 1;
int d = 3;
memset(nodes, 0, sizeof(nodes));
}
~Node() {
for (int i = 0; i < 26; ++i)
if (nodes[i])
delete nodes[i];
}
};
class ACTree {
Node root;
public:
void insert(char* str) {
Node *head = &root;
while(*str) {
int i = *str - 'a';
if(head->nodes[i] != NULL) head = head->nodes[i];
else {
head->nodes[i] = new Node(*str);
head = head->nodes[i];
}
++str;
}
head->m_isLeaf = true;
head->count += 1;
}
void constructACTree() {
queue<Node *> qu;
qu.push(&root);
while(!qu.empty()) {
Node * tmp = qu.front();
qu.pop();
for(int i = 0; i < 26; ++i) {
//tmp就是待处理节点的父节点
if (tmp->nodes[i]) {
if (tmp == &root) {
tmp->nodes[i]->falure = &root;
}
else {
Node * p = tmp->falure;
while (p) {
if (p->nodes[i]) {
tmp->nodes[i]->falure = p->nodes[i];
break;
}
p = p->falure;
}
if (p == NULL)
tmp->nodes[i]->falure = &root;
}//if else
qu.push(tmp->nodes[i]);
}//if
}//for
}//while
}
//假设不存在一个模式串是另一个模式串的子串
//不能统计匹配的关键词的个数
int match(char *str) {
int count = 0;
while (*str) {
char *p = str;
Node *n = &root;
while (n && p) {
int i = *p - 'a';
if (n->nodes[i]) {
n = n->nodes[i];
++p;
if (n->m_isLeaf) {
++count;
str = p;
break;
}
}
else {
n = n->falure;
}
}
if (n == NULL) {
++str;
}
}
return count;
}
//如果字符串s1..n匹配到trie树中的某个节点ni,设此时匹配的字符是sh...i, 那么ni的失败指针所指向的节点nj,必然可以匹配sk...i,其中,k>h
//即失败指针所指向的节点,这个节点到root的路径,必然是已经匹配字符串的子串
int countKeys(char *str) {
int count = 0;
Node *p = &root;//这个可以看做是主线查询
while(*str) {
int i = *str - 'a';
//如果p->nodes[i]不等于null,则跳出循环,继续在这个分支上查找;否则,就跳到另一个分支
while(p->nodes[i] == NULL && p != &root) p = p->falure;
p = p->nodes[i];//
//所有分支均不能匹配这个字串,所以要从头开始匹配
if(p == NULL)
p = &root;
Node *tmp = p;
while(tmp != &root && tmp->count != -1) {
count += tmp->count;
tmp->count = -1;//删除这个叶子
tmp = tmp->falure;
}
++str;
}
return count;
}
~ACTree() {
/* for (int i = 0; i < 26; ++i)
if (root.nodes[i])
delete root.nodes[i];*/
}
};
int main() {
int t;
scanf("%d", &t);
while (t--) {
ACTree tree;
int n;
scanf("%d", &n);
while(n--) {
scanf("%s", keyword);
tree.insert(keyword);
}
tree.constructACTree();
scanf("%s", desc);
printf("%d\n", tree.countKeys(desc));
}
return 0;
}