搜索关键字列表

时间:2013-09-24 23:05:42

标签: string algorithm search

我正在构建一个消息传递反垃圾邮件解决方案,我必须将收到的每条短信与一个关键字列表进行比较,如果短信中包含其中一个关键字,我就不得不删除它。

问题是搜索关键字列表的最佳算法是什么?例子在下面

text message received is "hi how are you, visit us at www.xyz.com" 

,列表示例在

之下
www.abc.com
www.xyz.com
...
...

2 个答案:

答案 0 :(得分:1)

如果有很多关键字,特别是有共同的前缀,trie可能会在这里运作良好。

我假设您想要子字符串,而不仅仅是单词,即给定关键字bah,它会在bah中找到bahama。修改这个以防止这种情况应该不难。

我还假设您没有关键字,并且它的子字符串是一个关键字(即bahbahama不能都是关键字)。迎合这一点也不应该太困难。

只是,对于字符串中的每个字符,开始在树的顶部搜索并继续搜索树中的每个现有指针。一旦其中一个指针到达一个有效的单词,按照你的意愿去做,并可能删除树中的所有指针。

<强>复杂度:

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;
  }