代码随想录算法训练营第九天| 28. 实现 strStr() 459.重复的子字符串 字符串总结 双指针回顾

 28. 实现 strStr()

给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回  -1 

题目链接:28. 找出字符串中第一个匹配项的下标 - 力扣(LeetCode)

思路:标标准准的kmp算法,可以我不会写,只能用土方法for循环了。

class Solution {
public:
    int strStr(string haystack, string needle) {
        int i=0;
        int j=0;
        int tmp=i;
        if(haystack.size()<needle.size())
            return -1;
        for(;i<haystack.size();i++){
            tmp=i;
            while(haystack[tmp]==needle[j]&&j<needle.size()){tmp++;j++;}
            if(j==needle.size()){
                return i;
            }
            j=0;
        }
        return -1;

    }
};

似乎是把KMP看懂了,先把KMP算法放这里吧

class Solution {
public:
    int strStr(string s, string p) {
        int n = s.size(), m = p.size();
        if(m == 0) return 0;
        //设置哨兵
        s.insert(s.begin(),' ');
        p.insert(p.begin(),' ');
        vector<int> next(m + 1);
        //预处理next数组
        for(int i = 2, j = 0; i <= m; i++){
            while(j and p[i] != p[j + 1]) j = next[j];
            if(p[i] == p[j + 1]) j++;
            next[i] = j;
        }
        //匹配过程
        for(int i = 1, j = 0; i <= n; i++){
            while(j and s[i] != p[j + 1]) j = next[j];
            if(s[i] == p[j + 1]) j++;
            if(j == m) return i - m;
        }
        return -1;
    }
};

459.重复的子字符串

给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。

题目链接:459. 重复的子字符串 - 力扣(LeetCode)

思路:开始时认为本题可以根据字母出现次数来解决,结果发现不充要,因为所有字母(不为0的)出现次数存在共同公因数时未必有循环字符串,是必要不充分。只能老老实实用字符串处理了。

思路(真):从2开始尝试子串重复次数,子串的重复次数应满足:1、2<=i<=字符串长度2、是字符串长度的因数。当找到可能得子串重复次数后,子串长度也能确定了。在按位确定子串是否循环至字符串末尾。效率竟然意外的不错。

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        int length=s.size();
        int cl;     //子串长度
        int i=2;    //子串重复次数
        while(i<=length){
            if(length%i)
            {
                ++i;continue;
            }
            cl=length/i;
            int k=1;                                //k*cl==按位比较时的偏移量
            for(int j=0;j<cl;j++){
                while(k<i&&s[j]==s[j+k*cl])++k;    //注意逻辑判断顺序不能更换
                if(k!=i)break;                     
                k=1;                               //勿忘重置k
                if(j==cl-1)return true;
                }
            i++;
            }
        return false;
        }
};

啊?😅

  • 如果一个字符串可以由多个重复子串构成,即具有循环节 设最小循环节用a来表示,他代表通过子串a重复多次可以构成s 即s换成a来表示就是aa···aaa,由多少个最小循环节a构成s,那么就有几个a
  • 找循环节一个一个对比比较麻烦,最简单方法就是s+s就可以直接增加多一倍的循环节
  • 假设原来s=aaaa,那ss=s+s=aaaa aaaa 因为是不断重复的循环节,可以通过简单的屏蔽的第一个字符,然后再在ss中寻找s 因为屏蔽第一个字符,即第一个最小循环节被破坏,所以找到的s应该是从第二个循环节开始
  • 但倘若不是由一个子串重复构成 即s=abcd,那s+s=abcd abcd,屏蔽掉第一个字符,又因不匹配,所以在ss中寻找s,一定是对应着新增s的位置,即s.size()处
class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        return (s + s).find(s, 1) != s.size();
    }
};

作者:力扣官方题解
链接:https://leetcode.cn/problems/repeated-substring-pattern/solutions/386481/zhong-fu-de-zi-zi-fu-chuan-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

字符串总结  

代码随想录 (programmercarl.com)

双指针回顾 

代码随想录 (programmercarl.com)

posted @ 2024-02-01 18:30  SandaiYoung  阅读(2)  评论(0编辑  收藏  举报