我正在构建一个消息传递反垃圾邮件解决方案,我必须将收到的每条短信与一个关键字列表进行比较,如果短信中包含其中一个关键字,我就不得不删除它。
问题是搜索关键字列表的最佳算法是什么?例子在下面
text message received is "hi how are you, visit us at www.xyz.com"
,列表示例在
之下www.abc.com
www.xyz.com
...
...
答案 0 :(得分:1)
如果有很多关键字,特别是有共同的前缀,trie可能会在这里运作良好。
我假设您想要子字符串,而不仅仅是单词,即给定关键字bah
,它会在bah
中找到bahama
。修改这个以防止这种情况应该不难。
我还假设您没有关键字,并且它的子字符串是一个关键字(即bah
和bahama
不能都是关键字)。迎合这一点也不应该太困难。
只是,对于字符串中的每个字符,开始在树的顶部搜索并继续搜索树中的每个现有指针。一旦其中一个指针到达一个有效的单词,按照你的意愿去做,并可能删除树中的所有指针。
<强>复杂度:强>
O(max(n2, mn))
其中m
是树中节点的数量,在最坏的情况下,虽然平均案例性能应该好很多。
示例:强>
所以,假设我们有关键字:
ab
b
caa
我们可能会得到一棵树:
o
/|\
a / | \ c
/ |b \
o o o
| b | a
o o
| a
o
(o
只是一个节点)
现在,对于输入字符串caab
,我们首先看一下c
:( x
表示树中的指针)
o
/|\
a / | \ c
/ |b \
o o x
| b | a
o o
| a
o
注意右边的新指针。
然后a
:
o
/|\
a / | \ c
/ |b \
x o o
| b | a
o x
| a
o
请注意左侧的新指针和右侧的指针。
然后a
:
o
/|\
a / | \ c
/ |b \
o o o
| b | a
o o
| a
x
注意左边的指针消失了,右边的指针消失了。
现在我们删除右侧的那个,因为我们找到了一个有效的单词。
然后b
:
o
/|\
a / | \ c
/ |b \
o x o
| b | a
o o
| a
o
注意中间的新指针,然后我们也会删除它,因为我们找到了一个有效的单词。
答案 1 :(得分:0)
你在说几个关键词?查看Boyer-Moore字符串搜索算法,它可能适用于您的目的,并且实现起来并不困难。这是从wikipedia article:
获取的java实现 /**
* Returns the index within this string of the first occurrence of the
* specified substring. If it is not a substring, return -1.
*
* @param haystack The string to be scanned
* @param needle The target string to search
* @return The start index of the substring
*/
public static int indexOf(char[] haystack, char[] needle) {
if (needle.length == 0) {
return 0;
}
int charTable[] = makeCharTable(needle);
int offsetTable[] = makeOffsetTable(needle);
for (int i = needle.length - 1, j; i < haystack.length;) {
for (j = needle.length - 1; needle[j] == haystack[i]; --i, --j) {
if (j == 0) {
return i;
}
}
// i += needle.length - j; // For naive method
i += Math.max(offsetTable[needle.length - 1 - j], charTable[haystack[i]]);
}
return -1;
}
/**
* Makes the jump table based on the mismatched character information.
*/
private static int[] makeCharTable(char[] needle) {
final int ALPHABET_SIZE = 256;
int[] table = new int[ALPHABET_SIZE];
for (int i = 0; i < table.length; ++i) {
table[i] = needle.length;
}
for (int i = 0; i < needle.length - 1; ++i) {
table[needle[i]] = needle.length - 1 - i;
}
return table;
}
/**
* Makes the jump table based on the scan offset which mismatch occurs.
*/
private static int[] makeOffsetTable(char[] needle) {
int[] table = new int[needle.length];
int lastPrefixPosition = needle.length;
for (int i = needle.length - 1; i >= 0; --i) {
if (isPrefix(needle, i + 1)) {
lastPrefixPosition = i + 1;
}
table[needle.length - 1 - i] = lastPrefixPosition - i + needle.length - 1;
}
for (int i = 0; i < needle.length - 1; ++i) {
int slen = suffixLength(needle, i);
table[slen] = needle.length - 1 - i + slen;
}
return table;
}
/**
* Is needle[p:end] a prefix of needle?
*/
private static boolean isPrefix(char[] needle, int p) {
for (int i = p, j = 0; i < needle.length; ++i, ++j) {
if (needle[i] != needle[j]) {
return false;
}
}
return true;
}
/**
* Returns the maximum length of the substring ends at p and is a suffix.
*/
private static int suffixLength(char[] needle, int p) {
int len = 0;
for (int i = p, j = needle.length - 1;
i >= 0 && needle[i] == needle[j]; --i, --j) {
len += 1;
}
return len;
}