KMP算法——俗稱看毛片算法

咳咳咳,這是看毛片算法的簡單介紹
首推一個博客,這個博客很優秀,我的KMP算法就是從上面學來的——https://www.cnblogs.com/yjiyjige/p/3263858.html

算法思想

假設母串是BACAACAAADH,子串是ACAACAD,
當匹配到下圖一步,指針i和j的位置明顯不匹配了,
在這裏插入圖片描述
腫麼辦,按照暴力的辦法應該是把指針i和j回溯到如下圖的位置再比較
在這裏插入圖片描述
但是,我們發現這樣時間複雜度就變得很不友好,
細心或者對KMP有接觸的朋友應該注意到了其實可以不回溯這麼遠,
其實可以回溯到如下圖的位置
在這裏插入圖片描述
爲什麼呢,因爲在子串中存在前三個字符和接下來的三個字符相同,
這樣,我們就可以保持i指針不變,將j指針回溯三個字符,然後接着繼續進行匹配操作,
從這個例子可以看出子串中有可能存在和開頭相等的子子串,式子表示如下
str.substring(0, k) = str.substring(m, n)
我們可以利用這個特性,減少已經匹配過的串儘量少的回溯
咳咳咳,先想清楚再看下面的,如果想不太明白,那也看看下面的,
下面的是重點,考試要考的
++++++++++++++++++++++++++華麗的分割線++++++++++++++++++++++++++++
弄明白KMP的主體思想思想之後,我們就開始關注怎麼實現了,
首先先看一個例子,如果當出現如下匹配失敗的時候
在這裏插入圖片描述
因爲橙色區域的和黃色區域的已經確認匹配,並且存在相等的情況,
所以回溯的時候,可以保持指針i不變,將指針j回溯到黃色區域的開頭那裏,如下圖
在這裏插入圖片描述
也就是下圖
在這裏插入圖片描述
也就是回溯到的位置是下標爲3的位置,從這個例子可以看出,
在母、子串匹配的時候,無論在哪個位置不匹配,都會存在一個回溯的值,
哪怕是第一個就不匹配,也可以回溯到-1的位置
下面那個就是對應位置回溯位置的數組
對於ACAACAD這個子串來說,其數組爲
在這裏插入圖片描述
關於代碼怎麼實現的,這個目前比較流行的是我下面給出的代碼,
這個代碼有兩個難點,一個是k = next[k],一個j–
結合我給的例子,慢慢揣摩就能明白,我抽象表達能力不太好,這裏就不誤導大家了,
大家也可以去看看我開頭推薦的那個博客,ta寫的挺詳細的,但是我沒看(主要是太笨了,不想看也看不懂),我都是看ta代碼慢慢研究出來的

上代碼

// 暴力匹配的算法,至於怎麼暴力,反正就是暴力,不要在意這些細節嘛
public int indexOf(String origin, String subStr) {
    int result = -1;
    for (int i=0; i<origin.length()-subStr.length(); i++) {
      boolean matching = true;
      for (int j=0; j<subStr.length(); j++) {
        if (origin.charAt(i+j) != subStr.charAt(j)) {
          matching = false;
          break;
        }
      }
      if (matching) {
        result = i;
        break;
      }
    }
    return result;
  }
// KMP算法的實現
public int indexOf(String origin, String subStr) {
    int result = -1;
    int i, j;
    i = j = 0;
    int[] next = getNext(subStr);
    while (i < origin.length()) {
      // 相等的情況
      if (subStr.charAt(j) == origin.charAt(i)) {
        i++;
        j++;
        if (j == subStr.length()) {
          result = i - j;
          break;
        }
      } else {  // 不等的情況
        j = next[j];
        if (j == -1) {
          i++;
          j = 0;
        }
      }
    }
    return result;
  }

// 獲取next數組
  public int[] getNext(String str) {
    int[] next = new int[str.length()];
    int k = next[0] = -1;
    // 其它博客都是while循環,這裏爲了體現j--這個的功能,就不用while了
    for (int j=1; j<str.length(); j++) { 
      if (-1 == k || str.charAt(j-1) == str.charAt(k)) {    // 第一次k不等於-1的時候是j=2的時候
        next[j] = ++k;
      } else {    // ACAACADH
        k = next[k];
        j--;    // 懂了這個就懂了整個算法
      }
    }
    return next;
  }

時間複雜度

O(m+n)

這個博主很懶,就寫了這麼多,並且博主智商捉急,腫麼辦,挺急的單就不在線等了,忙着找藥,有事留言

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章