LeetCode459:重复的子字符串

力扣459:重复的子字符串
【描述】
给出一个非空字符串,判断该字符串是否由子字符串重复组成。
例:
输入:“abab”
输出:“true”
输入:“abcd”
输出:“false”
kmp算法介绍
这也是一道可以用kmp算法解决的题目。为什么这么说?
这涉及到kmp算法中next数组的定义了:next 数组记录的是最长相等前后缀的长度。
最长相等前后缀的长度为 next[next.size() - 1],
如果一个长度为 n 的字符串 s 可以由它的一个长度为 n’ 的子串 s’ 重复多次构成,那么:

  • n 一定是 n’ 的倍数;
  • s’ 一定是 s 的前缀;

由于 next[n−1] 表示 s 具有长度为 next[n−1]+1 的完全相同的(且最长的)前缀和后缀。那么对于满足题目要求的字符串,一定有 n % (n - (next[n - 1])) == 0;
对于不满足题目要求的字符串,n 一定不是 n − next[n − 1] 的倍数。
因此,我们在预处理出 next 数组后,只需要判断 n 是否为 n − next[n − 1] 的倍数即可。

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

using namespace std;
/*
* Author: 酒馆店小二
* Description: 459.重复的子字符串
* Date: 2022-02-21 10:25:16 星期一
* FileName: leetcode459.cpp
* Location: D:\VSCODE_CPP\algorithm\kmp\leetcode459.cpp
*/
vector<int> kmpNext(const string &substr) {  // KMP next 数组
    int n = substr.size();
    vector<int> next(n);
    next[0] = 0;
    for (int i = 1, j = 0; i < n; ++i) { // 注意 i 从1开始
        // 要保证 j > 0,因为会用到 j - 1 做下标
        while (j > 0 && substr[i] != substr[j]) { // 前后缀不相同
            j = next[j - 1]; // 向前回退
        }
        if (substr[i] == substr[j]) { // 找到相同的前后缀
            j++;
        }
        next[i] = j; // 将 j(前缀的长度) 赋给next[i]
    }
    return next;
}

bool repeatedSubstringPattern(string s) {
    int len = s.size();
    if (len == 0) {
        return false;
    }
    vector<int> next(len);
    next = kmpNext(s);
    if (next[len - 1] != 0 && len % (len - (next[len - 1])) == 0) {
        return true;
    }
    return false;
}

int main(int argc, char* argv[]){
    string res = "abcabc";
    string test = "bnmk";
    bool ans = repeatedSubstringPattern(res);
    bool so = repeatedSubstringPattern(test);
    cout << ans << ", " << so << endl; 
    return 0;
}

在这里插入图片描述

修改于:2022.02.21
欲买桂花同载酒,终不似,少年游。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值