构建部分匹配表时KMP中第二个while循环的目的是什么?

时间:2016-08-04 02:26:49

标签: string algorithm computer-science string-matching knuth-morris-pratt

为KMP构建部分匹配表时:

void buildBackTable() { 
    int i = 0, j = -1; b[0] = -1; 
    while (i < m) { 
        while (j >= 0 && P[i] != P[j]) j = b[j]; //Why is this a while loop!?
        i++; j++;
        b[i] = j;
    }
}   

为什么第二次while循环不是有条件的呢?如:

void buildBackTable() { 
    int i = 0, j = -1; b[0] = -1; 
    while (i < m) { 
        if (j >= 0 && P[i] != P[j]) j = b[j]; //Why not?
        i++; j++;
        b[i] = j;
    }
}   

在我尝试的大多数例子中,当没有匹配时,此语句用于将j重置为-1,因此当下一次迭代到来时,我们比较字符串的第一个字符(P [j])在位置i(P [i])处的角色。

1 个答案:

答案 0 :(得分:1)

首先要澄清一下,OP的符号m代表字符串P的长度。请注意,b的长度为m+1。 (这是其中一个实现,虽然到目前为止并非最自然的符号,这可能导致混淆)

让我们看看buildBackTable()的目的是什么。基本上,对于生成的数组bb[i]将存储最大值j,例如那个j < iP[0..j-1] == P[i-j..i-1]b[0]=-1

理解以下属性并不困难:

  1. b[i] <= b[i-1] + 1
  2. 如果b[i] = j,那么对于任何k < j,s.t P[0..k-1] == P[i-k..i-1],我们都知道b[j] >= k。同时,显然是b[i] > b[j]b[i] = 0
  3. 这意味着我们可以通过k等方式轻松枚举b[i] -> b[b[i]] -> b[b[b[i]]]...从最大到最小的值。

    此枚举允许我们跳过P的前缀并找到最大值j,s.t。 P[0..j-1] == P[i-j..i-1]P[i] == P[j]

    关于你的问题,当条件检查(没有循环失败)时,只考虑字符串aaaac。然后是b[4] = 3。但是b[5] = 0。只有条件检查,您才能获得b[5]=3