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为例:

前缀串后缀串
AB
ABAB
ABAAAB
ABAABAAB
ABAABABAAB

这就是第六个元素所有的前缀和后缀串,最后一个不计在内,所以最长相等前缀后缀AB,长度为2,所以next数组中C的位置就是2。
这个模式串的next数组如下:

s:ABAABCABA
next:-100112012

求出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);
    }
};
    原文作者:KMP算法
    原文地址: https://blog.csdn.net/thinkerleo1997/article/details/78170242
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞