算法训练第九天|28. 实现 strStr() 、459.重复的子字符串

字符串|28. 实现 strStr() 、459.重复的子字符串


28. 实现 strStr()

自己审题思路

这道题刚开始只能想到暴力解法

代码(暴力解法1):

class Solution {
public:
    int strStr(string haystack, string needle) {
        int n = haystack.size(), m = needle.size();
        for (int i = 0; i + m <= n; i++) {
            bool flag = true;
            for (int j = 0; j < m; j++) {
                if (haystack[i + j] != needle[j]) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                return i;
            }
        }
        return -1;
    }
};

代码(暴力解法2):

class Solution {
public:
    int strStr(string s, string p) {
        int n = s.size(), m = p.size();
        for(int i = 0; i <= n - m; i++){
            int j = i, k = 0; 
            while(k < m && s[j] == p[k]){
                j++;
                k++;
            }
            if(k == m) return i;
        }
        return -1;
    }
};

看完代码随想录题解后的收获

了解了KMP算法,难点在于next数组的建立。将next数组的建立理解为前缀和后缀的匹配过程,next数组的构建的代码会好些出来一些。

代码(自己完成):
class Solution {
public:
    void getNext(string& pattern, vector<int>& next) {
        int j = 0;
        next[0] = 0;
        for (int i = 1; i <  pattern.size(); i++) {
            while(j  > 0 && pattern[j] != pattern[i]) {
                j = next[j -1];
            }
            if (pattern[j] == pattern[i]) j++;
            next[i] = j;
        }
    }

    int strStr(string& haystack, string& needle) {
        vector<int> next(needle.size(), 0);
        getNext(needle, next);
        int j = 0;
        int match = 0;
        int i = 0;
        while (i < haystack.size()) {
            while(j > 0 && needle[j] != haystack[i]) {
                j = next[j - 1];
            }
            if (j == 0 && needle[j] != haystack[i]) i++;

            match = i - j;
            while (needle[j] == haystack[i]) {
                j++;
                i++;
                if (j == needle.size()) return match;
            }
        }
        return -1;
    }
};

next直接用数组就好

代码(代码随想录)
class Solution {
public:
    void getNext(int* next, const string& s) {
        int j = 0;
        next[0] = 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;
        }
    }
    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 - 1];
            }
            if (haystack[i] == needle[j]) {
                j++;
            }
            if (j == needle.size() ) {
                return (i - needle.size() + 1);
            }
        }
        return -1;
    }
};

参考详解


459.重复的子字符串

自己审题思路

暴力解法,一个for循环用来选取子串,一个for循环用子串拼接字符串

代码

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
    if(s.size()==1) return false;
    string temp="",str="";
    for(int i=0;i<s.size()/2;++i)
    {
        temp+=s[i];
        while(str.size()<=s.size())
        {
            str+=temp;
            if(str.compare(s)==0)
            {
               return true;
            }
        }
        str="";
    }
    return false;
    }
};

看完代码随想录题解后的收获

1、 移动匹配
判断字符串s是否由重复子串组成,只要两个s拼接在一起,里面还出现一个s的话,就说明是由重复子串组成。
2、KMP
在由重复子串组成的字符串中,最长相等前后缀不包含的子串就是最小重复子串

代码(移动匹配)
class Solution {
public:
    bool repeatedSubstringPattern(string s) {
    if(s.size()==1) return false;
    string temp="",str="";
    for(int i=0;i<s.size()/2;++i)
    {
        temp+=s[i];
        while(str.size()<=s.size())
        {
            str+=temp;
            if(str.compare(s)==0)
            {
               return true;
            }
        }
        str="";
    }
    return false;
    }
};
代码(KMP)
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();
        if (next[len - 1] != 0 && len % (len - (next[len - 1] )) == 0) {
            return true;
        }
        return false;
    }
};

参考详解


今日感悟

KMP算法next数组的求解涉及到动态规划,理解了这点KMP算法就比较好写了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容