算法思想

1、KMP算法

设有两串字符,第一串为主串,第二串为副串,求副串在主串的匹配index头。

主要是求next数组,感性认识是副串的前后缀匹配程度:

       - "A"的前缀和后缀都为空集,共有元素的长度为0;

  - "AB"的前缀为[A],后缀为[B],共有元素的长度为0;

  - "ABC"的前缀为[A, AB],后缀为[BC, C],共有元素的长度0;

  - "ABCD"的前缀为[A, AB, ABC],后缀为[BCD, CD, D],共有元素的长度为0;

  - "ABCDA"的前缀为[A, AB, ABC, ABCD],后缀为[BCDA, CDA, DA, A],共有元素为"A",长度为1;

  - "ABCDAB"的前缀为[A, AB, ABC, ABCD, ABCDA],后缀为[BCDAB, CDAB, DAB, AB, B],共有元素为"AB",长度为2;

  - "ABCDABD"的前缀为[A, AB, ABC, ABCD, ABCDA, ABCDAB],后缀为[BCDABD, CDABD, DABD, ABD, BD, D],共有元素的长度为0。

class Solution {
public:
    int strStr(string haystack, string needle) {
        int m = haystack.length(), n = needle.length();
        if (!n) {
            return 0;
        }
        vector<int> lps = kmpProcess(needle);
        for (int i = 0, j = 0; i < m; ) {
            if (haystack[i] == needle[j]) { 
                i++;
                j++;
            }
            if (j == n) {
                return i - j;
            }
            if ((i < m) && (haystack[i] != needle[j])) {
                if (j) {
                    j = lps[j - 1];
                }
                else {
                    i++;
                }
            }
        }
        return -1;
    }
private:
    vector<int> kmpProcess(string& needle) {
        int n = needle.length();
        vector<int> lps(n, 0);
        for (int i = 1, len = 0; i < n; ) {
            if (needle[i] == needle[len]) {
                lps[i++] = ++len;
            } else if (len) {
                len = lps[len - 1];
            } else {
                lps[i++] = 0;
            }
        }
        return lps;
    }
};

 

class Solution {
public:
    vector<int> GetNext(string P)
    {
        vector<int> next(P.size(), 0);
        int p_len = P.size();
        int i = 0;   // P 的下标
        int j = -1;
        next[0] = -1;

        while (i < p_len - 1)
        {
            if (j == -1 || P[i] == P[j])
            {
                i++;
                j++;
                next[i] = j;
            }
            else
                j = next[j];
        }
        vector<int> v2(next.size(), 0);
        copy(next.begin(), next.end(), v2.begin());
        return v2;
    }

    //在 S 中找到 P 第一次出现的位置 /
    int strStr(string S, string P)
    {



        int i = 0;  // S 的下标
        int j = 0;  // P 的下标
        int s_len = S.size();
        int p_len = P.size();
        if (!p_len) return 0;

        vector<int> next = GetNext(P);


        while (i < s_len && j < p_len)
        {
            if (j == -1 || S[i] == P[j])  // P 的第一个字符不匹配或 S[i] == P[j]
            {
                i++;
                j++;
            }
            else
                j = next[j];  // 当前字符匹配失败,进行跳转
        }

        if (j == p_len)  // 匹配成功
            return i - j;

        return -1;
    }
};
//优化版

/* P 为模式串,下标从 0 开始 */
void GetNextval(string P, int nextval[])
{
    int p_len = P.size();
    int i = 0;   // P 的下标
    int j = -1;  
    nextval[0] = -1;

    while (i < p_len - 1)
    {
        if (j == -1 || P[i] == P[j])
        {
            i++;
            j++;
          
            if (P[i] != P[j])
                nextval[i] = j;
            else
                nextval[i] = nextval[j];  // 既然相同就继续往前找真前缀
        }
        else
            j = nextval[j];
    }
}

 

posted @ 2018-09-03 22:47  热之雪  阅读(188)  评论(0编辑  收藏  举报