LeetCode-28 实现strStr() KMP算法的学习

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/repeated-string-match

题目描述

给定两个字符串 a 和 b,寻找重复叠加字符串 a 的最小次数,使得字符串 b 成为叠加后的字符串 a 的子串,如果不存在则返回 -1。

注意:字符串 "abc" 重复叠加 0 次是 "",重复叠加 1 次是 "abc",重复叠加 2 次是 "abcabc"。

示例 1:

输入:a = "abcd", b = "cdabcdab"
输出:3
解释:a 重复叠加三遍后为 "abcdabcdabcd", 此时 b 是其子串。


示例 2:

输入:a = "a", b = "aa"
输出:2


示例 3:

输入:a = "a", b = "a"
输出:1


示例 4:

输入:a = "abc", b = "wxyz"
输出:-1

解题思路

对于这种问题,暴力法也叫朴素求解法是将两个字符串一个一个比较,可以肯定复杂度为O(mn),但是通过KMP算法,可以将复杂度下降到O(m+n).

KMP算法的原理是,在匹配过程中,匹配字符串之中会有重复的字符,遍历过后如果使用朴素算法,会有多次的遍历,可以使用一个next数组,将有相同前缀的标记起来,在遍历的时候便可以跳过遍历前缀的过程,大大提高了解题效率

next数组构建过程如下:(借用宫水三叶大佬的两张图)

 

 

 

 

 

 

 这样,在两个字符串比较过程中,如果发现字符比较不相同,可以直接跳到与当前字符串有相同前缀的字符上,不需要从头开始进行计算。

代码展示

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

运行结果

 

 

posted @ 2022-02-25 16:24  过客匆匆,沉沉浮浮  阅读(85)  评论(0编辑  收藏  举报