給定目標串 haystack 和模式串 needle ,返回 needle 在 haystack 中第一次出現的位置下標,若 needle 不是 haystack 的子串則返回 -1。
1. Brute-Force Algorithm(暴力算法 / 簡單模式匹配)
我自己寫了一種雙層循環的
1 int strStr(string haystack, string needle) { 2 if (needle.empty()) return 0; 3 int m = haystack.size(), n = needle.size(); 4 for (int i = 0; i <= m - n; i++) { 5 for (int j = 0; j < n; j++) { 6 if (needle[j] != haystack[i + j]) 7 break; 8 if (j == n - 1) 9 return i; 10 } 11 } 12 return -1; 13 }
看了答案發現了一種更高效的方法,雖然時間復雜度同樣是 O(m*n),但只要一層循環,非常Nice!
1 int strStr(string haystack, string needle) { 2 if (needle.empty()) return 0; 3 int i = 0, j = 0; 4 int m = haystack.size(), n = needle.size(); 5 while (i < m && j < n) { 6 if (haystack[i] == needle[j]) { 7 i++; 8 j++; 9 } else { 10 i = i - j + 1; 11 j = 0; 12 } 13 if (j == n) 14 return i - j; 15 } 16 return -1; 17 }
2. KMP算法
算法講解可以參考 http://www.61mon.com/index.php/archives/183/ ,講解的已經很好了。
KMP的時間復雜度僅為 O(m+n),因為當出現子串與主串某處不匹配時,並不會將遍歷主串的下標 i 回溯,而是利用得到的 next 數組將模式子串向右“滑動”盡可能遠的一段距離,繼續進行比較,提高了效率。
next 數組的求解是關鍵,它是基於模式子串的最長前后綴,next[i] = needle[0] 到 needle[i - 1] 的字符串的最長相同前后綴的長度。
1 void getNext(string needle, vector<int> &next) { 2 int i = 0, j = -1; 3 // j 表示最長相同前后綴的長度 4 next[0] = j; 5 while (i < needle.size()) { 6 // j == -1 為邊界條件判斷, j = next[j] 可能使 j 退回到 -1 7 if (j == -1 || needle[i] == needle[j]) { 8 i++; 9 j++; 10 next[i] = j; 11 } else { 12 j = next[j]; 13 } 14 } 15 } 16 17 int strStr(string haystack, string needle) { 18 if (needle.empty()) return 0; 19 int i = 0, j = 0; 20 int m = haystack.size(), n = needle.size(); 21 vector<int> next(n + 1); 22 getNext(needle, next); 23 while (i < m && j < n) { 24 if (j == -1 || haystack[i] == needle[j]) { 25 i++; 26 j++; 27 } else { 28 j = next[j]; 29 } 30 if (j == n) 31 return i - j; 32 } 33 return -1; 34 }
改進的KMP算法
1 void getNextval(string needle, vector<int> &nextval) { 2 int i = 0, j = -1; 3 nextval[0] = j; 4 while (i < needle.size()) { 5 if (j == -1 || needle[i] == needle[j]) { 6 i++; 7 j++; 8 // 生成 nextval 數組 9 if (needle[i] != needle[j]) 10 nextval[i] = j; 11 else 12 nextval[i] = nextval[j]; 13 } else { 14 j = nextval[j]; 15 } 16 } 17 } 18 19 int strStr(string haystack, string needle) { 20 if (needle.empty()) return 0; 21 int i = 0, j = 0; 22 int m = haystack.size(), n = needle.size(); 23 vector<int> nextval(n + 1); 24 getNextval(needle, nextval); 25 while (i < m && j < n) { 26 if (j == -1 || haystack[i] == needle[j]) { 27 i++; 28 j++; 29 } else { 30 j = nextval[j]; 31 } 32 if (j == n) 33 return i - j; 34 } 35 return -1; 36 }