重复的子字符串

28. 找出字符串中第一个匹配项的下标

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

示例 1:

输入:haystack = "sadbutsad", needle = "sad"
输出:0
解释:"sad" 在下标 0 和 6 处匹配。
第一个匹配项的下标是 0 ,所以返回 0 。

示例 2:

输入:haystack = "leetcode", needle = "leeto"
输出:-1
解释:"leeto" 没有在 "leetcode" 中出现,所以返回 -1 。

方法一:枚举

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        int n = s.size();
        for (int i = 1; i * 2 <= n; ++i) {
            if (n % i == 0) {
                bool match = true;
                for (int j = i; j < n; ++j) {
                    if (s[j] != s[j - i]) {
                        match = false;
                        break;
                    }
                }
                if (match) {
                    return true;
                }
            }
        }
        return false;
    }
};

 方法二:双指针

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        int n = s.size();
        for (int len = 1; len <= n / 2; len++) {
            if (n % len == 0) {
                bool isMatch = true;
                for (int i = 0; i < n; i += len) {
                    for (int j = 0; j < len; j++) {
                        if (s[i + j] != s[j]) {
                            isMatch = false;
                            break;
                        }
                    }
                    if (!isMatch) {
                        break;
                    }
                }
                if (isMatch) {
                    return true;
                }
            }
        }
        return false;
    }
};

方法三:字符串匹配

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        return (s + s).find(s, 1) != s.size();
    }
};

(s+s)将字符串与其自身进行拼接,目的是利用拼接后的字符串的特性来判断字符串是否由重复子串组成。 在拼接得到的新字符串上调用find成员函数查找指定子串在当前字符串在子串总出现的位置。第二个参数从索引一的位置开始查找(跳过拼接字符串开头与原字符串s起始重复的部分)。将 find  函数返回的位置与原字符串 s  的长度进行比较。如果查找结果不等于原字符串的长度,说明在拼接字符串中从索引 1  开始找到了与 s  匹配的子串,也就意味着原字符串 s  是由重复子串组成的,此时返回 true  ;否则返回 false  。

 

方法四:KMP算法

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        if(s.size()==0){
            return false;
        }
        int j=0;
        int next[s.size()];
        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 len=s.size();
        if(next[len-1]!=0&&len%(len-next[len-1])==0){
            return true;
        }
        return false;
    }
};

如果s的长度为0,则返回false。定义一个变量j初始化为0。用来记录后续next的索引。定义一个整数类型的数组next,数组大小与字符串s长度相同,用于存储s的部分匹配信息。初始化next的的一个元素为0。遍历字符串s。当j大于0且当前字符s[i]与匹配字符s[j]不相等时进入循环。通过next数组回溯j的位置,目的是找到一个合适的j,使得从该位置开始能继续匹配。回溯j的位置,利用好已经计算好的next值,让j跳到合适的位置继续匹配。如果当前字母m[i]与m[j]相等,j加加。将当前位置i的最长前后缀记录到next数组中。定义一个变量冷并赋值为字符串s。如果next数组的最后一个元素不为0且字符串长度能被最小重复子串长度整除,则返回true。否则返回false。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值