【问题标题】:String match in sliding window滑动窗口中的字符串匹配
【发布时间】:2013-03-01 06:09:43
【问题描述】:

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

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

您无法访问该文件,但可以访问一个函数 FetchNextChar(),它一次提供一个字符。

要匹配的模式是a a b

您如何计算点击总数?

这就是我的想法。

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

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

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 

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

有什么想法吗?

【问题讨论】:

  • 为什么不用KMP算法?
  • @Imposter 如果你想提及它,请做link to an algorithm
  • 这是一个已解决的问题。请参阅 Gusfield 1997。从实用的角度来看,最好使用的算法是 Boyer-Moore 算法。
  • 有什么好的 DS 可以有效地存储文件中的文本并滑动窗口?理想情况下,我们只想将模式的长度存储在缓冲区中以进行比较。
  • 您希望只匹配aab,还是只是一个示例,并且您想知道一种通用算法来计算文本流中任何字符串的出现次数?

标签: string algorithm pattern-matching trie


【解决方案1】:

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

我们可以看到,每次读取'b' 时,我们都会继续state=0,如果我们在state=2 上,模式出现的次数就会增加一。当 '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

【讨论】:

    【解决方案2】:

    这可以通过使用Rabin–Karp algorithm 为滑动窗口计算rolling hash 来有效解决,一个简单的滚动散列函数是对字符的ASCII 码求和,但是您可以使用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};
    

    这是上述算法打印匹配数的伪代码:

    stream = "aaabaabaabbab";
    pattern = "aab";
    queue window;
    
    patternHash = 0;
    for ch in pattern:
        patternHash = patternHash + primes[ch - 'a']
    
    first = readFromStream(stream)
    window.enqueue(first)
    windowHash = primes[first - 'a']
    for i = 0 to pattern.size():
        ch = readFromStream(stream)
        window.enqueue(ch)
        windowHash = windowHash + primes[ch - 'a']
    
    count = 0
    for i = pattern.size() to stream.size():
        if windowHash == patternHash
            if window == pattern
                count = count + 1
        ch = readFromStream(stream)
        window.enqueue(ch)
        windowHash = windowHash - primes[window.first() - 'a']
        windowHash = windowHash + primes[ch - 'a']
        window.dequeue()
    
    print count
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-23
      • 2017-08-08
      • 1970-01-01
      • 1970-01-01
      • 2020-03-23
      • 2015-02-28
      • 2021-09-08
      • 1970-01-01
      相关资源
      最近更新 更多