力扣题号:459. 重复的子字符串
一、题目描述
给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。
二、示例
示例 1:
输入: s = "abab" 输出: true 解释: 可由子串 "ab" 重复两次构成。
示例 2:
输入: s = "aba" 输出: false
示例 3:
输入: s = "abcabcabcabc" 输出: true 解释: 可由子串 "abc" 重复四次构成。 (或子串 "abcabc" 重复两次构成。)
提示:
1 <= s.length <= 104
s
由小写英文字母组成
三、求解思路
四、代码实现
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
int KMPSearch(char* pat, char* txt);
void computeNextArray(char* pat, int M, int* Next);
// 暴力求解法
int bruteForce(char* str) {
int len = strlen(str);
// 遍历所有可能的子串长度
for (int sub_len = 1; sub_len <= len / 2; ++sub_len) {
// 如果字符串长度不能被子串长度整除,则该子串不可能构成原字符串
if (len % sub_len != 0)
continue;
// 提取子串
char *substring = (char*)malloc((len + 1)*sizeof(char));
strncpy(substring, str, sub_len);
substring[sub_len] = '\0';
// 初始计数器,用于记录通过重复子串构造了多少次
int count = 1;
// 指向当前比较位置的指针
const char* ptr = str + sub_len;
// 尝试用子串匹配整个字符串
while (*ptr != '\0') {
if (strncmp(ptr, substring, sub_len) == 0) {
ptr += sub_len;
++count;
}
else {
break; // 不匹配,跳出循环
}
}
// 如果整个字符串都能由子串构成,且刚好用完子串次数,返回1
if (*ptr == '\0' && count * sub_len == len)
return 1;
}
// 如果没有找到合适的子串,返回0
return 0;
}
// 移动匹配法
int Moving_matching(char* str) {
int len = strlen(str);
char* str2 = (char*)malloc((2 * len - 1) * sizeof(char));
str2[2 * len - 2] = '\0';
// 合并两个相同的字符串
char* p = str + 1;
char* p2 = str2;
while (*p) {
*p2++ = *p++;
}
p = str;
while (*p && *p2) {
*(p2++) = *(p++);
}
// 使用KMP算法进行匹配
int res = KMPSearch(str, str2);
return res == -1 ? 0: 1;
}
// KMP求解法
int KMP_Solutuon(char* str) {
int len = strlen(str);
// 计算Next数组。
int* Next = (int*)malloc(len * sizeof(int));
computeNextArray(str, len, Next);
if (Next[len - 1] != 0 && len % (len - (Next[len - 1])) == 0) {
return 1;
}
return 0;
}
// 构建next数组
void computeNextArray(char* pat, int M, int* Next) {
int j = 0;
Next[0] = 0;
for (int i = 1; i < M; i++) {
// 前后缀不匹配
while (j > 0 && pat[i] != pat[j]) {
j = Next[j - 1];
}
// 前后缀匹配
if (pat[i] == pat[j]) {
j++;
}
Next[i] = j;
}
}
// KMP字符串匹配
int KMPSearch(char* pat, char* txt) {
int M = strlen(pat);
int N = strlen(txt);
int* Next = (int*)malloc(M * sizeof(int));
computeNextArray(pat, M, Next);
int i = 0; // 文本串指针
int j = 0; // 模式串指针
while (i < N) {
if (pat[j] == txt[i]) {
j++;
i++;
}
if (j == M) {
return i - j; // 匹配成功
}
else if (i < N && pat[j] != txt[i]) {
if (j != 0) {
j = Next[j - 1];
}
else {
i++;
}
}
}
return -1; // 未找到匹配
}
int main() {
char str[1000] = { 0 };
char pat[1000] = { 0 };
fgets(str, 1000, stdin); // 获取一个字符串
int length = strlen(str);
str[length - 1] = '\0';
cout << "暴力求解:" << bruteForce(str) << endl;
cout << "移动匹配求解:" << Moving_matching(str) << endl;
cout << "KMP求解:" << KMP_Solutuon(str) << endl;
return 0;
}