28. 找出字串中第一個匹配項的下標 Golang實現

wochh發表於2024-10-10

題目描述:

給你兩個字串 haystack 和 needle ,請你在 haystack 字串中找出 needle 字串的第一個匹配項的下標(下標從 0 開始)。如果 needle 不是 haystack 的一部分,則返回 -1 。

示例 1:
輸入:haystack = "sadbutsad", needle = "sad"
輸出:0
解釋:"sad" 在下標 0 和 6 處匹配。
第一個匹配項的下標是 0 ,所以返回 0 。

思路分析:

在進入主要流程之前應該進行非法行為斷定:

  • 因為在題目中已經表示了兩個字串不會為空,所以不需要判斷是否為空的情況
  • 如果模式串比目標串要長,則不可能有符合條件的下標,於是這種情況非法,其餘情況正常繼續。

找一個模式串在目標串中的起始位置,典型的KMP演算法。有兩種實現方法:暴力迴圈和KMP方法。他們的區別在於暴力法的複雜度是O(n^2)和O(m+n)。

暴力迴圈法:

就是依次從目標串的第一個位置不斷開始找,如果達到模式串的長度時的字串仍然相同,那就說明查詢成功。否則從下一個開始的位置進行查詢,具體實現如下,重點關注一下兩個迴圈的指標的設計方案。用模式串的長度進行指標挪動可以減少一次迴圈。

點選檢視程式碼
func strStr(haystack string, needle string) int {
    if len(needle) == 0 {
        return 0
    }
    var i, j int
    // i不需要到len-1
    for i = 0; i < len(haystack)-len(needle)+1; i++ {
        for j = 0; j < len(needle); j++ {
            if haystack[i+j] != needle[j] {
                break
            }
        }
        // 判斷字串長度是否相等
        if len(needle) == j {
            return i
        }
    }
    return -1
}

KMP演算法

字首: 包含第一個字元的子串
KMP演算法的核心就是利用之前的匹配過程的資訊(最長公共字首。因為他在匹配的過程中記錄最長公共子串的長度,他相當於是對稱的===:前面幾個長度的字元和後面幾個字元的長度是相同的,並且如果next陣列(記錄當前公共子串的長度)的值不為0,就說明到目前為止模式串和目標串的元素是有相同的的存在的。
即有三種情況:
p []int //尋找LPS的string
next []int //儲存LPS的陣列
length int //當前最長的LPS長度

  • 當前字串相同的,匹配成功。length++,向後移動
  • 匹配失敗:當前字元和之前的字元也沒有能夠組成的LPS,這裡需要遞迴尋找,具體操作方法為:
    else if length!=0 {
    //只有這個判斷條件沒有發生i++,即找到相同的為止,要麼重新找。這就是遞迴的體現。
    length = lps[length-1]
    給一個具體的例子:(來自知乎@涼拌炒雞蛋)
    image
    當找到下標13的c的時候,發生不匹配現象,但是之前串的length = 5,如果從頭開始匹配複雜度就又上去了,所以依然要利用之前的匹配資訊,將length-1直到為0看是否匹配。length-1的效果:其實就是不斷縮短字首的長度,看到最新不匹配的位置是否能透過減少字元的方法匹配上,他減少2個字元就匹配上了。
  • 實在不匹配就置為0,向後繼續匹配。

程式碼:

點選檢視程式碼
func computeLPSArray(pat string) []int {
  lps:=make([]int,len(pat))
  length:= 0
   //從位置1開始遍歷,找最長字首長度
   for i := 1; i < len(pat);{
       if pat[i]==pat[length] {
           length++
           lps[i] = length
           i++
       }else if length!=0 {
           //只有這個判斷條件沒有發生i++,即找到相同的為止,要麼重新找。這就是遞迴的體現。
           length = lps[length-1]
       }else {
           lps[i] = 0
           i++
       }
   }
   return lps
}

相關文章