滚动哈希溢出/负结果保护

时间:2018-12-11 18:08:33

标签: java string algorithm rabin-karp

这个问题与rolling-hash非常相似,但是关于溢出/负结果的一些细节我仍然不清楚。

我也已经检查了这个Rabin-Karp implementation,并且在下面有问题:

txtHash = (txtHash + Q - RM*txt.charAt(i-M) % Q) % Q;

我了解以下表达式可能会给出否定的结果:

txtHash - RM*txt.charAt(i-M)

第一个问题

  • 如果我们总是将Q(一个大质数)相加,由于溢出会导致结果为负数吗?
    • 如果不是,为什么不呢?如果是,那么仅在结果为负数时才进行此加法运算吗?

第二个问题

如果我们暂时不在乎负数,写下面的表达式是否正确?

txtHash = (txtHash - RM*txt.charAt(i-M)) % Q;

第三个​​问题,这部分让我最困惑:

让我们假设当我们添加Q时不会发生溢出。为什么在前导位数上有最左边的%Q操作?

txtHash = (txtHash + Q - RM*txt.charAt(i-M) % Q ) % Q;

我已经阅读了我链接的答案,并根据Aneesh的回答,如果我正确理解了下面的表达式,则应该类似:

hash = hash - ((5 % p)*(10^2 %p) %p)

txtHash = (txtHash + Q - RM*txt.charAt(i-M) % Q) % Q;

但是我不明白为什么它们如此相似,因为在哈希示例中,%p不是针对先前的哈希值计算的,但是对于txtHash,我们也会计算%Q高于先前的哈希。

1 个答案:

答案 0 :(得分:1)

  

第一个问题:

     

如果我们总是加一个大质数的Q,由于溢出会导致结果为负数吗?           如果没有,为什么不呢?如果是,那么仅在结果为负数时才执行此加法运算吗?

通常选择质数Q,以便2Q仍不会溢出类型。

现在让我们看看。

  • txtHash的范围是0到Q-1。
  • RM*txt.charAt(i-M)大。
  • RM*txt.charAt(i-M) % Q的范围是0到Q-1。
  • txtHash - RM*txt.charAt(i-M) % Q是从-(Q-1)到Q-1。
  • txtHash + Q - RM*txt.charAt(i-M) % Q的范围是1到2Q-1。

所以,只要2Q-1不溢出,上面的表达式就可以了。

  

第二个问题:

     

如果我们暂时不在乎负数,写下面的表达式是否正确?

     

txtHash = (txtHash - RM*txt.charAt(i-M)) % Q;

是的,如果% Q始终给出从0到Q-1的结果(例如在Python中),那么上面的表达式就可以了。

  

第三个问题,这部分使我最困惑:

     

让我们假设当我们添加Q时不会发生溢出。为什么在前导位数上有最左边的%Q操作?

     

txtHash = (txtHash + Q - RM*txt.charAt(i-M) % Q ) % Q;

假设我们删除了最左边的% Q。 然后让我们再次估算:

  • txtHash的范围是0到Q-1。
  • RM*txt.charAt(i-M)大。
  • 多大?从0到(Q-1)* CharCode。
  • txtHash - RM*txt.charAt(i-M)从-(Q-1)*(CharCode-1)到Q-1。
  • txtHash + Q - RM*txt.charAt(i-M)从-(Q-1)*(CharCode-2)到2Q-1。

仍然可能是负面的。 不是我们想要的。