代码随想录Day9

104 阅读2分钟

28. 实现 strStr()

力扣题目链接

文章讲解

思路:没什么好说的,kmp算法重中之重,应该反复思考和琢磨至少一种kmp的next数组的获取函数,建议直接看carl的讲解视频。目前我都采用的是原next数组的方法,毕竟贪多嚼不烂,二刷建议实现所有方法。

#include <iostream>
using namespace std;

class Solution {
public:
    void getNext(int* next, const string& s) {
        int j = 0;
        next[0] = 0;
        for (int i = 1; i < s.size(); ++i) {
            // 不相等的情况,j往前回跳
            while (j > 0 && s[i] != s[j]) {
                j = next[j - 1];
            }
            // 相等的情况,next数组更新
            if (s[i] == s[j]) {
                j++;
            }
            next[i] = j;
        }
    }
    // 时间复杂度: O(n + m)
    // 空间复杂度: O(m)

    int strStr(string haystack, string needle) {
        if (needle.size() == 0) {
            return 0;
        }
        int next[needle.size()];
        getNext(next, needle);
        int j = 0;
        for (int i = 0; i < haystack.size(); ++i) {
            while (j > 0 && haystack[i] != needle[j]) {
                // j通过next数组找到回跳的位置
                j = next[j - 1];
            }
            if (haystack[i] == needle[j]) {
                // 检查 haystack 和 needle 在位置 i 和 j 处的当前字符是否相等。如果相等,它将 j 增加1,以移动到 needle 中的下一个字符。
                j++;
            }
            if (j == needle.size()) {
                // 检查 j 是否已经到达 needle 字符串的末尾。如果是,表示在 haystack 中找到了完全匹配,因此返回匹配的起始索引 (i - needle.size() + 1) 
                return (i - needle.size() + 1);
            }
        }
        // 走到此行说明未找到匹配子串,返回-1
        return -1;
    }
};

459.重复的子字符串

力扣题目链接

文章讲解

思路:属于kmp算法的应用之一。

#include <iostream>
using namespace std;

class Solution {
public:
    void getNext (int* next, const string& s) {
        next[0] = 0;
        int j = 0;
        for (int i = 1; i < s.size(); ++i) {
            while (j > 0 && s[i] != s[j]) {
                j = next[j - 1];
            }
            if (s[i] == s[j]) {
                j++;
            }
            next[i] = j;
        }
    }
    bool repeatedSubstringPattern(string s) {
        if (s.size() == 0) {
            return false;
        }
        int next[s.size()];
        getNext(next, s);
        int len = s.size();
        /**
        在KMP算法中,next数组的含义是在字符串中每个位置i之前的最长相同前缀后缀的长度。如果字符串可以由重复的子串构成,那么最后一个位置的next值就是子串的长度。
        假设字符串s可以由重复的子串构成,且子串的长度为len - next[len - 1]。那么字符串s的长度len必然可以被(len - next[len - 1])整除,因为每个子串的长度都是(len - next[len - 1])。
        另外,如果字符串s可以由重复的子串构成,那么next数组的最后一个元素next[len - 1]一定不为零。因为如果为零,说明整个字符串s没有相同的前缀和后缀,即没有重复的子串。
        因此,满足next[len - 1]不为零,并且len能够被(len - next[len - 1])整除,可以判断字符串s是否可以由重复的子串构成。*/
        if (next[len - 1] != 0 && len % (len - (next[len - 1])) == 0) {
            return true;
        }
        return false;
    }
};