为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])处的角色。
答案 0 :(得分:1)
首先要澄清一下,OP的符号m
代表字符串P
的长度。请注意,b
的长度为m+1
。 (这是其中一个实现,虽然到目前为止并非最自然的符号,这可能导致混淆)
让我们看看buildBackTable()
的目的是什么。基本上,对于生成的数组b
,b[i]
将存储最大值j
,例如那个j < i
,P[0..j-1] == P[i-j..i-1]
,b[0]=-1
。
理解以下属性并不困难:
b[i] <= b[i-1] + 1
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
。 这意味着我们可以通过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
。