URL:http://www.lintcode.com/zh-cn/problem/strstr/
對於一個給定的 source 字符串和一個 target 字符串,你應該在 source 字符串中找出 target 字符串出現的第一個位置(從0開始)。如果不存在,則返回 -1。
暴力法:
從文本串的第一個元素開始比對,如果和模式串相符,那麼就是返回匹配位置,否則就從文本串下一個開始比對,AC代碼:
class Solution {
public:
/**
* Returns a index to the first occurrence of target in source,
* or -1 if target is not part of source.
* @param source string to be scanned.
* @param target string containing the sequence of characters to match.
*/
int strStr(const char *source, const char *target) {
// write your code here
if (!(source && target))
return -1;
int len_source = strlen(source);
int len_target = strlen(target);
if (len_target == 0)
return 0;
if (len_source == 0)
return -1;
for (int i = 0; i < len_source; i++) {
for (int j = 0, s = i; j < len_target && s < len_source; j++, s++) {
if (source[s] != target[j])
break;
else {
if (j == len_target - 1)
return i;
}
}
}
return -1;
}
};
int main() {
char source[] = "abcsde";
char target[] = "a";
Solution so;
cout << so.strStr(source, target);
}
KMP算法:
KMP算法是D.E.Knuth,J.H.Morris和V.R.Pratt三位大佬同時研發出來的算法,可以使字符串匹配的時間複雜度下降到
在KMP算法中,對於每一個模式串我們會事先計算出模式串的內部匹配信息,在匹配失敗時最大的移動模式串,以減少匹配次數。
以字符串 ABAABCABA 爲例:
我們需要求出保存每個元素位置的最長相等前綴後綴長度的next數組,
什麼是前綴後綴?以第六個元素C
爲例:
前綴串 | 後綴串 |
---|---|
A | B |
AB | AB |
ABA | AAB |
ABAA | BAAB |
ABAAB | ABAAB |
這就是第六個元素所有的前綴和後綴串,最後一個不計在內,所以最長相等前綴後綴是AB,長度爲2,所以next數組中C的位置就是2。
這個模式串的next數組如下:
s: | A | B | A | A | B | C | A | B | A |
---|---|---|---|---|---|---|---|---|---|
next: | -1 | 0 | 0 | 1 | 1 | 2 | 0 | 1 | 2 |
求出next數組後,假設在文本串第五個C
的位置匹配失敗時,那就將它從最長相等前綴後綴的後綴處滑動到前綴處開始匹配。
AC代碼:
class Solution {
public:
/**
* Returns a index to the first occurrence of target in source,
* or -1 if target is not part of source.
* @param source string to be scanned.
* @param target string containing the sequence of characters to match.
*/
void getNext(const char *p, int next[]) {
int nLen = (int) strlen(p);
next[0] = -1;
int k = -1;
int j = 0;
while (j < nLen - 1) {
if (k == -1 || p[j] == p[k]) {
++j;
++k;
next[j] = k;
} else {
k = next[k];
}
}
}
int kmp(const char *source, const char *target) {
int target_nexts[1000];
getNext(target, target_nexts);
int ans = -1;
int i = 0;
int j = 0;
int pattern_len = strlen(target);
int n = strlen(source);
while (i < n) {
if (j == -1 || source[i] == target[j]) {
++j;
++i;
} else
j = target_nexts[j];
if (j == pattern_len) {
ans = i - pattern_len;
break;
}
}
return ans;
}
int strStr(const char *source, const char *target) {
// write your code here
if (!(source && target))
return -1;
int len_source = strlen(source);
int len_target = strlen(target);
if (len_target == 0)
return 0;
if (len_source == 0)
return -1;
return kmp(source, target);
}
};