Python:Rabin-Karp算法散列

标签 python string algorithm pattern-matching

我实现 Rabin-Karp 算法只是为了好玩。我遇到了这个伪代码:

    RABIN -KARP -MATCHER (T, P, d, q)
    1 n = T.length
    2 m = P.length
    3 h = d^(m-1) mod q
    4 p=0
    5 t= 0
    6 for i = 1 to m
    / preprocessing
    /
    7 p = (dp + P [i]) mod q
    8 t = (dt + T [i]) mod q
    9 for s = 0 to n-m
    / matching
    /
    10     if p == t
    11         if P [1... m] == T [s + 1...s + m]
    12             print “Pattern occurs with shift” s
    13     if s < n-m
    14         t  = (d(t-T[s + 1]h) + T [s + m + 1]) mod q

我在 Python 2.7 中是这样实现的:

def Rabin_Karp_Matcher(text, pattern, d, q):
    n = len(text)
    m = len(pattern)
    h = pow(d,m-1)%q
    p = 0
    t =0
    result = []
    for i in range(m): # preprocessing
        p = (d*p+ord(pattern[i]))%q
        t = (d*t+ord(text[i]))%q
    for s in range(n-m):
        if p == t: # check character by character
            match = True
            for i in range(m):
                if pattern[i] != text[s+i]:
                    match = False
                    break
            if match:
                result = result + [s]
        if s < n-m:
                t = (d*(t-ord(text[s+1])*h)+ord(text[s+m]))%q #index out of bounds here
    return result

其中 result 是一个列表,其中包含模式文本中的索引。

我的代码无法在 3141592653589793 中找到 26 我怀疑它与伪代码第 14 行定义的哈希码有关。谁能帮忙解决这个问题。

我传入了以下参数:

P = "26" T = “3141592653589793” d = 257 q = 11

P 和 T 必须是字符串/字符数组

最佳答案

这是您的代码的工作版本:

def Rabin_Karp_Matcher(text, pattern, d, q):
    n = len(text)
    m = len(pattern)
    h = pow(d,m-1)%q
    p = 0
    t = 0
    result = []
    for i in range(m): # preprocessing
        p = (d*p+ord(pattern[i]))%q
        t = (d*t+ord(text[i]))%q
    for s in range(n-m+1): # note the +1
        if p == t: # check character by character
            match = True
            for i in range(m):
                if pattern[i] != text[s+i]:
                    match = False
                    break
            if match:
                result = result + [s]
        if s < n-m:
            t = (t-h*ord(text[s]))%q # remove letter s
            t = (t*d+ord(text[s+m]))%q # add letter s+m
            t = (t+q)%q # make sure that t >= 0
    return result
print (Rabin_Karp_Matcher ("3141592653589793", "26", 257, 11))
print (Rabin_Karp_Matcher ("xxxxx", "xx", 40999999, 999999937))

输出是:

[6]
[0, 1, 2, 3]

第一步,检查是否 text[0..m] == pattern。在第二步,您要检查是否 text[1..m+1] == pattern。因此,您从散列中删除 text[0](此时它乘以您预先计算的 h):t = (t-h*ord(text[s ]))%q。然后,向其中添加 text[m]:t = (t*d+ord(text[s+m]))%q。在下一步中,您删除 text[1] 并添加 text[m+1],依此类推。 t = (t+q)%q 行在那里是因为负数模 q 产生 (-q; 0] 范围内的余数,我们希望它在 [0; q) 范围内。

请注意,您要检查总共 n-m+1 个子字符串,而不是 n-m,因此正确的循环是 for s in range(n -m+1)。通过第二个例子检查(在“xxxxx”中找到“xx”)。

另外值得注意的是:

  1. 如果 m 很大,h = pow(d,m-1)%q 行可能会太慢。最好在每次 m-2 乘法后取模 q

  2. 这个算法在最坏的情况下仍然是 O(nm)。使用 text="a"*100000pattern="a"*50000,它会找到 50001 个文本子串与模式匹配的位置,并检查它们所有字符一个字符。如果您希望您的代码在这种极端情况下能够快速运行,您应该跳过逐个字符的比较并找到一种方法来处理误报(即哈希值相等但字符串不相等)。选择一个大素数 q 可能有助于将误报概率降低到可接受的水平。

关于Python:Rabin-Karp算法散列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22216948/

相关文章:

python - 如何在 python 中链接目录(相当于 Linux 命令 ln -s)?

python - 如何访问该模型类中的数据?

python - 如何在Python中计算XGBoost分类器的联合特征贡献?

java - 在 Java 中迭代字符串时,哪种方法更快,为什么?

Java对json格式的限制

algorithm - Mandelbrot 集的平滑着色算法

c++ - 如何找到存储在 C++ vector 中的对象的类方法?

python - 从非 ascii 字符串解码 Python 3 中的转义 unicode

php - PHP中删除字符串中与字母、数字、特定符号、汉字不匹配的字符

algorithm - 是否有一种算法可以使用任意规则将通用算术公式转换为另一个算术公式?