我正在尝试使用KMP算法实现strstr。这是维基百科中给出的算法。 KMP算法的时间复杂度为O(n),其中n是较大字符串的大小。
vector<int> KMP(string S, string K)
{
vector<int> T(K.size() + 1, -1);
vector<int> matches;
if(K.size() == 0)
{
matches.push_back(0);
return matches;
}
for(int i = 1; i <= K.size(); i++)
{
int pos = T[i - 1];
while(pos != -1 && K[pos] != K[i - 1]) pos = T[pos];
T[i] = pos + 1;
}
int sp = 0;
int kp = 0;
while(sp < S.size())
{
while(kp != -1 && (kp == K.size() || K[kp] != S[sp])) kp = T[kp];
kp++;
sp++;
if(kp == K.size()) matches.push_back(sp - K.size());
}
return matches;
}
我不明白这个算法的复杂程度如何是O(n)。任何人都可以解释这段代码的复杂性是如何O(n)?
答案 0 :(得分:2)
我认为你担心的是,两种情况下的内循环每次外循环迭代最多可执行m次,从而导致你提到的最坏情况复杂性。事实上,这不可能发生。
归纳地看第一个循环通知,因为T []初始化为-1,我们得到T [0]&lt; 0,T [1]&lt; 1,...你可以看到我们实际上有T [i]&lt;我有意义,因为T [i]是一个指向我们正在搜索的字符串的指针。
现在转到第二个嵌套循环,看看每个外循环迭代只增加一次kp,而内部while循环只能减少它。由于kp低于-1并且从0开始,在整个方法的整个生命周期中,我们总共只能执行一次内循环迭代,而不是外循环迭代,因为否则kp最终会小于 - 1。所以第二个嵌套循环只能花费总共O(n)。
第一个嵌套循环看起来比较棘手,直到你注意到在外循环开始时从T [i-1]读取pos,然后在结尾写为T [i] = pos + 1,所以pos是等价的我们刚刚分析了嵌套循环中的kp,并且相同的参数表明成本最多为O(K.size())。