7-8 好后缀 (10分)
我们称一个字符串的后缀为好后缀,如果它满足如下条件:
(1)它在字符串中至少出现2次;
(2)满足条件(1)的最长者。
请编写程序计算一个字符串的好后缀长度,注意一个字符串不能称为自己的后缀。
输入输出描述
输入格式:
输入为一个字符串,包含不超过10^5个字母。
输出格式:
输出为一个整数,表示输入字符串的好后缀长度。
样例
输入样例1:
xacbacba
输出样例1:
4
输入样例2:
yxxabacaba
输出样例2:
3
输入样例3:
abc
输出样例3:
0
解题
首先看前缀函数定义:
根据定义知,next[i] = k;k就是以i为末尾下标的子串中,最长的相同真前后缀的长度,因此本题先将字符串逆转,然后就是求最大next[i]问题
代码
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 1e5 + 2;
char str[maxn];
int next_[maxn];
int ans;
void get_next(int next_[], char str[]) {
int len = strlen(str);
next_[0] = 0;
for (int i = 1; i < len; i++) {
/*j表示上一个匹配的长度, j - 1就是j长度的前缀的末尾下标*/
int j = next_[i - 1];
/*如果不匹配, j == 0 或 不匹配时退出循环*/
while (j > 0 && str[i] != str[j]) j = next_[j - 1]; //向前回溯查找
if (str[i] == str[j]) j++; //能够匹配
next_[i] = j;
ans = max(ans, j);
}
}
int main() {
scanf("%s", str);
reverse(str, str + strlen(str));
get_next(next_, str);
// for (int i = 0; i < strlen(str); i++) {
// printf("%d ", next_[i]);
// }
printf("%d\n", ans);
system("pause");
return 0;
}
扩充KMP匹配算法
#include <bits/stdc++.h>
using namespace std;
class Solution {
vector<int> get_next(const string &s) {
vector<int> pi(s.size());
pi[0] = 0;
for (int i = 1; i < s.size(); i++) {
int j = pi[i - 1];
while (j > 0 && s[i] != s[j]) j = pi[j - 1];
if (s[i] == s[j]) j++;
pi[i] = j;
}
return pi;
}
public:
int strStr(string haystack, string needle) {
if (needle.size() == 0) return 0;
vector<int> pi = get_next(needle);
// pi[i] = j, 下标0~i 字符串, 对应的前缀值为j
int j = 0;
for (int i = 0; i < haystack.size(); i++) {
// 如果不匹配, 缩小j, 第[j]个不匹配, 找到[j - 1]个切换
while (j > 0 && needle[j] != haystack[i]) j = pi[j - 1];
if (haystack[i] == needle[j]) j++;
if (j == needle.size()) { // 匹配完毕
return i - j + 1;
}
}
return -1;
}
};