用于在字符串中搜索子串的快速算法

时间:2009-11-19 18:38:38

标签: java algorithm string search

我想要一个有效的算法(或库),我可以在Java中使用它来搜索字符串中的子字符串。

我想做的是:

给定输入字符串 - INSTR

  

“BCDEFGH”

一组候选字符串 - CAND

  

“AB”,“CDE”,“FG”,“H”,“IJ”

INSTR

中查找匹配为的任何 CAND 字符串

在这个例子中,我会匹配“CDE”,“FG”和“H”(但不是“AB”和“IJ”)

可能有数千个候选字符串(在CAND中),但更重要的是,我将进行数百万次搜索,因此我需要它快速。

我想使用char数组。此外,我并不喜欢建筑解决方案,例如分发搜索 - 只是在本地进行搜索的最有效的功能/算法。

此外,CAND和INSTR中的所有字符串都将相对较小(<50个字符) - 即目标字符串INSTR相对于候选字符串不长。


更新我应该提到,CAND字符串集在所有INSTR值中都是不变的。

更新我只需要知道有匹配 - 而且我不需要知道匹配是什么。

最终更新 由于实施简单,我选择尝试AhoCorsick和Rabin-Karp。 因为我有可变长度模式,所以我使用了一个修改过的Rabin-Karp,它会散列每个模式的前n个字符,其中n是最小模式的长度,N则是我的滚动子字符串搜索窗口的长度。 对于Aho Corsick,我使用了this

在我的测试中,我在两篇文章新闻论文中搜索了1000种模式,平均分为1000次迭代等... 标准化完成时间为:

AhoCorsick :1

RabinKarp :1.8

天真搜索(检查每种模式并使用string.contains):50


*描述以下答案中提到的算法的一些资源:

http://www.seas.gwu.edu/~simhaweb/cs151/lectures/module5/module5.html

http://www.cs.princeton.edu/courses/archive/spr09/cos226/lectures/18SubstringSearch-2x2.pdf

http://www-igm.univ-mlv.fr/~lecroq/string/index.html *

10 个答案:

答案 0 :(得分:26)

答案 1 :(得分:11)

将候选字符串集转换为确定性有限状态自动机,然后以线性时间运行输入字符串。标准书籍中详细介绍了将单个字符串转换为DFS。您可以通过首先构造一个非确定性自动机然后确定它来转换一组字符串。这可能会在自动机大小的最坏情况下产生指数性爆炸,但之后的搜索速度很快;特别是如果目标字符串很长并且候选人很短,那就会很好。

答案 2 :(得分:6)

这是正则表达式的用途。如上所述,有限状态自动机是您所需要的,但这正是标准正则表达式匹配器的实现方式。

在java中,您可以编写如下内容:

StringBuilder sb = new StringBuilder();
bool first = true;
for (String subStr : substrings) {
    if (first)
        first = false;
    else
        sb.append('|');
    sb.append(escape(subStr));
}
Pattern p = Pattern.compile(sb.toString());

方法escape应该转义任何在正则表达式中具有特殊含义的字符。

答案 3 :(得分:5)

Rabin-Karp multiple pattern search似乎是最快的。

答案 4 :(得分:2)

您可能需要查看Aho-Corasick algorithm及相关算法。我不知道任何实现这一点的库,但是这是解决这个问题的经典方法。

答案 5 :(得分:2)

同时检查Boyer-Moore algorithm是否有单字符串模式匹配。

答案 6 :(得分:2)

我们可以利用字符串的小尺寸(<50 char)为这种情况构建一个超快算法,但代价是内存。

我们可以在一次哈希中散列INSTR的所有可能子串,这将耗费O(n ^ 2)时间。然后,无论CAND字符串的数量如何,查找都将为O(1)。值得拥有大量的CAND字符串。

如果INSTR很大,那么我们可以构建一个后缀数组而不对它进行排序,这样顶部项目最长(= N),底部项目是INSTR的最后一个字符。现在对于每个CAND字符串,只要从顶部搜索长度(CAND)&lt; = length(后缀)。每个比较都是O(n)。

答案 7 :(得分:0)

另一种解决方案是使用suffix array作为 INSTR 由于 INSTR 很小,您可以使用冒泡排序对其进行排序。

之后,您可以在O(logN)时间内搜索特定的 CAND 字符串,
其中N =长度(suffix_array)=长度(INSTR)。

答案 8 :(得分:0)

Here是Java中快速字符串搜索算法的一些实现。

答案 9 :(得分:0)

import java.util.Scanner;

public class StringMatch 
{
    static int temp,i=0,j=0; static boolean flag=true,matcher=false;

    static String str=null,mstr=null;static char astr[],amstr[];

    static void getter(){
        Scanner sc = new Scanner(System.in);
        str = sc.nextLine();
        //String str="today is Monday"; 
        astr=str.toCharArray();
         mstr = sc.nextLine();
        //String mstr="is"; 
         amstr=mstr.toCharArray();
    }

    static void stringMatch(){
        while(i<astr.length){
            if(astr[i]==amstr[j]){
            while((j!=amstr.length)&&flag){temp=i;
                if(astr[i]!=amstr[j]) {flag=false;matcher=false;}
                else{matcher=true;}
                i++;j++;
                //System.out.println(i+"\t"+j);
            }if(matcher==true)break;i=temp;}i++;j=0;flag=true;

        }
        if(matcher==true) {System.out.println("true");}
        else    {System.out.println("false");}
    }

    public static void main(String[] args) {

    StringMatch.getter();
    StringMatch.stringMatch();

    }
}