LeetCode初級演算法之字串:28 實現 strStr() 函式
實現 strStr() 函式
題目地址:https://leetcode-cn.com/problems/implement-strstr/
給定一個 haystack 字串和一個 needle 字串,在 haystack 字串中找出 needle 字串出現的第一個位置 (從0開始)。如果不存在,則返回 -1。
示例 1:
輸入: haystack = "hello", needle = "ll"
輸出: 2
示例 2:
輸入: haystack = "aaaaa", needle = "bba"
輸出: -1
說明:
當 needle 是空字串時,我們應當返回什麼值呢?這是一個在面試中很好的問題。對於本題而言,當 needle 是空字串時我們應當返回 0 。這與C語言的 strstr() 以及 Java的 indexOf() 定義相符。
解法一:暴力解法
本題就是要實現一個indexOf函式,首先想到的就是雙指標在兩個串中比較。
暴力解法(BF)就依次掃描如果有相同的同步繼續,出現不同就中斷了,模式串回到起點主串回到下個開頭點。也就是說主串的長度會遍歷完,剩下的看模式串掃到什麼時候中斷。在最差的情況下每次模式串遍歷到最後一箇中斷主串最末端才匹配到那就是O(n*m)
邊界
- 索引越界
細節
- 迴圈結束條件
- haystack空返回0
- haystack比needle短返回-1
public int strStr(String haystack, String needle) { char[] hay = haystack.toCharArray(); char[] need = needle.toCharArray(); int h = hay.length; int n = need.length; int i=0,j=0; while(j < h && i < n){ if(hay[j] == need[i]){ i++; j++; }else { j=j-i+1; i=0; } } if(i >= n) return j-i; else return -1; }
解法二:擷取子串
除了兩個指標依次比較之外,判斷一個串是否含另一個串直接去依次擷取目標長度的子串,判斷有無相等的子串。這裡擷取我直接用的substring方法,這個也實現過很多次了,怎麼寫都一樣但我們一定要知道它的實現是怎樣的才能客觀的分析它的複雜度,這裡它就是一次遍歷。因此下面程式碼的解法也是一個兩層的遍歷
public int strStr(String haystack, String needle) { int n = needle.length(); int h = haystack.length(); for (int i = 0; i < h - n + 1; i++) { if (haystack.substring(i, i + n).equals(needle)) { return i; } } return -1; }
其實這種解法和解法一是一模一樣只不過前者把擷取和比較直接寫了出來,它比解法一優的點只是少遍歷了後面短的部分一個是h * (?)另一個是(h-n+1)* (?),是因為兩層遍歷分開寫可以這樣做。外面遍歷子串的開頭,裡面再遍歷子串與模式串是否相等。而解法一放到了一個迴圈也做到了這個邏輯
總結
字串匹配演算法算是一個比較經典的演算法,也是在計算機領域實際應用超多的演算法。上面無論是解一還是解二其實都是全遍歷比較。許多科學家都發明瞭更多減少比較次數的方式,比如RK演算法、BM演算法以及KMP演算法。這些在這裡暫時不介紹。之後在其他系列會出單篇講解這類以及其他的演算法。