滑动窗口中的字符串匹配

时间:2013-03-01 06:09:44

标签: string algorithm pattern-matching trie

假设您有一个包含以下字符串的文件

a a a b a a b a a b b a b 

您无权访问该文件,但只能访问一次提供一个字符的函数FetchNextChar()。

并且匹配的模式是a a b

你如何计算总点击次数?

这就是我的想法。

  1. 如果获取的字符是模式的第一个字符('a'),则将其添加到队列
  2. 如果匹配下一个模式
  3. 的字符,则开始为下一个字符添加/创建链接列表

    所以在第一次获取后我们有

    Pattern -a 
    Queue - a 
    
    Then 
    
    Pattern -a  a 
    Queue[0] a->a 
    Queue[1] a
    
    
    3rd 
    Pattern    a    a    b
    Queue[0]   a -->a--> a    //doesn't match, dequeue
    Queue[1]        a-> a
    Queue[2]             a 
    

    我认为这会有效,但我看到的问题是,如果有多个字符与模式的第一个字符匹配,我将不断添加到队列中,因此继续增加列表。

    有什么想法吗?

2 个答案:

答案 0 :(得分:3)

您可以使用基于状态的算法:

three state algorithm

我们可以看到,每次读取'b'时,我们都会继续state=0,如果我们在state=2上,则模式发生次数会增加1。当读取'a'时,我们会明确转到state=2所界定的下一个状态。

这是一个实现算法的python脚本

stream = ['a','a','a','b','a','a','b','a','a','b','b','a','b']

state = 0 
nbMatch = 0

for c in stream:
    if c=='a':
        if state==0 or state==1:
            state = state+1
        #if state == 2: state=2
    else: #c=='b'
        if state==2:
            nbMatch = nbMatch+1
        state = 0
    print c, "   state=", state
print nbMatch

答案 1 :(得分:2)

使用Rabin–Karp algorithm计算滑动窗口的rolling hash可以有效地解决这个问题,一个简单的滚动哈希函数是对字符的ASCII码求和,但是你可以使用这个{{1}数组1}}为了减少碰撞,我测试了这些素数,并在一个大而相似的字符串和模式匹配上给了我一些碰撞:

primes

以下是上述算法的伪代码,用于打印匹配计数:

primes[] = {13 , 7963 , 17443 , 27527 , 37879 , 48673 , 59407 , 70729 , 81883 , 93251 , 104789 , 116531 , 128239 , 139969 , 151783 , 163883 , 176159 , 188029 , 200257 , 212447 , 224831 , 237283 , 249517 , 262217 , 274661 , 287173};