LintCode 字符串查找(暴力法+KMP)

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.KnuthJ.H.MorrisV.R.Pratt三位大佬同時研發出來的算法,可以使字符串匹配的時間複雜度下降到O(m+n) 的線性複雜度。

在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);
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章