[算法導論]#5 KMP算法復雜度證明


引言

KMP算法應該是看了一次又一次,比賽的時候字符串不是我負責,所以學到的東西又還給網上的博客了……

退役后再翻開看,看到模板,心想這不是\(O(n^2)\)的復雜度嗎?

有兩個循環也不能看做是\(O(n^2)​\)的,這要用到攤還分析.

模板

這里用到的模板是算競上的

  • calc_next()
    Next[1] = 0;
    for (int i = 2, j = 0; i <= n; ++i) {
        while (j > 0 && a[i] != a[j + 1]) j = Next[j];
        if (a[i] == a[j + 1]) ++j;
        Next[i] = j;
    }
  • kmp()
   for (int i = 1, j = 0; i <= m; ++i) {
        while (j > 0 && (j == n || b[i] != a[j + 1]))j = Next[j];
        if (b[i] == a[j + 1])++j;
        f[i] = j;
    }

可以發現上下兩個函數挺像的,Next[i]含義就是模式串以\(i\)結尾的子串([1..i]的后綴)與模式串的前綴能匹配的最長長度

證明

觀察發現有兩個操作:

  • 匹配成功:j++,這個代價是1
  • 匹配失敗: j=Next[j]還要經過while循環,這個代價未知

根據記賬法,假設每個平攤代價是2,對於每個匹配成功的操作,其中1元用來j++,另1元就存起來,給后面匹配失敗時用:

而當失配的時候,就會用到銀行存款,最壞的情況當然就是用光了所有存款,但可以發現每個匹配的操作分配兩個時間代價是完全足夠的

換句話說,你使用存款肯定得要求銀行有存款,而每次j++操作都會存1元,在當前j前面必然每個位置都是有大於等於1的存款

所以復雜度就是j++次數的兩倍,也就是匹配串的長度 \(2n\)

根據平攤分析要求\(\check c_i \ge c_i\),平攤代價設置為\(2\)是完全滿足的

綜上所述:KMP算法兩個函數的總體運算次數為\(2n+2m\),復雜度是\(O(n+m)\)

總結

也不知道這樣分析對不對,如果只是感性理解的話足夠了.

也有勢能法的做法,但是這樣的話就要定義勢能函數,我覺得記賬法還是好理解一點.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM