题目描述
给你一个非空模板串S,一个文本串T,问S在T中出现了多少次

方法一:暴力求解

求解思路
对于本题目要求出模板串S在文本串T中出现的次数,我们想到直接从文本串T的第一个位置往后寻找模板串S长度的子串,然后拿出来和S比较即可,并且我们设置res变量来记录相同的个数。

图片说明

解题代码

class Solution {
public:
    int kmp(string S, string T)
    {
        if(S.empty() || S.size() > T.size()) return 0; // 边界
        int hyres = 0, next[S.size() + 1];
        next[0] = -1;
        for(int pre = -1, cur = 0; cur < S.size();)
        {
            if(pre == -1 || S[pre] == S[cur])
            {   //暴力匹配
                pre++;
                cur++;
                next[cur] = pre;
            }
            else pre = next[pre];
        }
        for(int pattern = 0, cur = 0; cur < T.size();)
        {   //模板串匹配
            if(pattern == -1 || S[pattern] == T[cur])
            {
                pattern++;
                cur++;
                if(pattern == S.size())
                {   //如果完全匹配
                    hyres++; // 结果加1
                    pattern = next[pattern];
                }
            }
            else pattern = next[pattern];
        }
        return hyres; // 返回结果
    }
};

复杂度分析
时间复杂度:一层循环加上一遍字符串遍历,因此时间复杂度为,N为循环,M为字符串子串的长度。
空间复杂度:没有引入额外的内存地址空间,因此空间复杂度为

方法二:KMP优化求解

求解思路
对于字符串子串匹配算法,我们使用KMP进行求解,首先构建一个next数组,用next[i]来表示模板串S中最长公共前缀的结束的下标,并且next[0]赋值-1。接着进行匹配,若匹配成功则两个字符串同步前进,若匹配失败则继续往前搜索到next数组中的位置,若为完全匹配,则跳到当前子串起始位置后一个,并更新到next的最后一个匹配值,来重新匹配下一个字符串。

图片说明

解题代码

class Solution {
public:
    int kmp(string S, string T) {
        int n = T.length(); // 保存T的长度
        int m = S.length(); // 保存S的长度
        int hyres = 0;
        vector<int> next(m + 1); // 声明next数组
        next[0] = -1; // next数组从-1开始
        int k = -1;
        for(int i = 0; i < m;)
        {  //初始化next数组
            if(k == -1 || S[k] == S[i])
            {
                k++;
                i++;
                next[i] = k;
            }
            else
                k = next[k];
        }
        k = 0; // 每次next数组从0开始,后面访问都会+1
        for(int i = 0; i < n;)
        {
            if(k == -1 || T[i] == S[k]) 
            {   //若是匹配,k 与 i 一同加
                k++;
                i++;
                if(k == m)
                {   //找到一个,将k置为next最大值
                    hyres++; // 结果加1
                    k = next[k];
                }
            }
            else //否则继续往前搜索
                k = next[k];
        }
        return hyres; // 返回结果
    }
};

复杂度分析
时间复杂度:一层循环,因此时间复杂度为
空间复杂度:因为引入next数组,所以空间复杂度为,N为next数组的长度。