A. DS串应用--KMP算法
学习KMP算法,给出主串和模式串,求模式串在主串的位置
算法框架如下,仅供参考
输入
第一个输入t,表示有t个实例
第二行输入第1个实例的主串,第三行输入第1个实例的模式串
以此类推
输出
第一行输出第1个实例的模式串的next值
第二行输出第1个实例的匹配位置,位置从1开始计算,如果匹配成功输出位置,匹配失败输出0
以此类推
输入:
3
qwertyuiop
tyu
aabbccdd
ccc
aaaabababac
abac
输出:
-1 0 0
5
-1 0 1
0
-1 0 0 1
8
#include <iostream>
#include <queue>
#include <string>
using namespace std;
class myString {
private:
string mainstr;
int size;
void GetNext(string p, int next[]);
int KMPFind(string p, int pos, int next[]);
public:
myString();
~myString();
void SetVal(string sp);
int KMPFindSubstr(string p, int pos);
};
int myString::KMPFindSubstr(string p, int pos) {
int i;
int L = p.length();
int* next = new int[L];
GetNext(p, next);
for (i = 0; i < L; i++) {
cout << next[i] << ' ';
}
cout << endl;
int v = -1;
v = KMPFind(p, pos, next);
delete[]next;
return v;
}
void myString::GetNext(string p, int* next) {
next[0] = -1; next[1] = 0;
int len = p.length(), temp = 0;
for (int i = 2; i < len; i++) {
while (p[i - 1] != p[temp] && temp > 0) {
temp = next[temp];
}
if (p[i - 1] == p[temp]) {
temp++;
}
next[i] = temp;
}
}
int myString::KMPFind(string p, int pos, int* next) {
int i = pos; int j = 0;
while (j != p.length() && i != size) {
if (mainstr[i] == p[j]) {
i++;
j++;
}
else {
j = next[j];
}
if (j == -1) {
i++;
j++;
}
}
if (j == p.length()) {
return i - j + 1;
}
else {
return -1;
}
}
myString::myString() {
size = 0;
mainstr = '\0';
}
myString::~myString() {
size = 0;
mainstr = '\0';
}
void myString::SetVal(string sp) {
mainstr.assign(sp);
size = sp.length();
}
int main() {
int t = 0;
string p1, sp1;
cin >> t;
while (t--) {
myString a;
myString b;
cin >> sp1;
cin >> p1;
a.SetVal(sp1);
int ans = a.KMPFindSubstr(p1, 0);
if (ans == -1) {
cout << "0" << endl;
}
else {
cout << ans << endl;
}
}
return 0;
}
B. DS串应用—最长重复子串
求串的最长重复子串长度(子串不重叠)。例如:abcaefabcabc的最长重复子串是串abca,长度为4。
输入
测试次数t
t个测试串
输出
对每个测试串,输出最长重复子串长度,若没有重复子串,输出-1.
输入:
3
abcaefabcabc
szu0123szu
szuabcefg
输出:
4
3
-1
//#include<iostream>
//#include<string>
//using namespace std;
//int find(string s) {
// int s_len = (int)s.length();
// int max=0;
// for (int i = 0; i < s_len; i++) {
//
// }
//}
//int main() {
// int n;
// cin >> n;
// while (n--) {
// string s;
// int len = find(s);
//
// }
//}
//
#include<iostream>
#include<string>
using namespace std;
int Findd(string str)
{
int len = str.length();
int maxx = 0;
for (int i = 0; i < len; i++)
{
for (int j = len - 1; j > i; j--)
{
string st = str.substr(i, j - i);
int len1 = st.length();
int fron = str.find(st);
int aft = str.rfind(st);
if (fron != aft && maxx < j - i)
{
if (len1 + fron <= aft)
maxx = j - i;
}
}
}
return maxx;
}
int main()
{
int t;
cin >> t;
while (t--)
{
string str;
string st;
cin >> str;
int in = Findd(str);
if (!in)
cout << in - 1 << endl;
else
cout << in << endl;
}
return 0;
}
C. DS串应用--串替换
给出主串、模式串、替换串,用KMP算法找出模式串在主串的位置,然后用替换串的字符替换掉模式串
本题只考虑一处替换的情况,如果你想做的完美一些,能够实现多处替换那
可能需要考虑模式串和替换串长度不一致的情况
输入
第一个输入t,表示有t个实例
第二行输入第1个实例的主串,第三行输入第1个实例的模式串,第四行输入第1个实例的替换串
以此类推
输出
第一行输出第1个实例的主串
第二行输出第1个实例的主串替换后结果,如果没有发生替换就输出主串原来的内容。
以此类推
输入:
3
aabbccdd
bb
ff
aaabbbccc
ddd
eee
abcdef
abc
ccccc
输出:
aabbccdd
aaffccdd
aaabbbccc
aaabbbccc
abcdef
cccccdef
#include <iostream>
#include<string>
using namespace std;
void getnext(string str, int next[])
{
int j = 0, k = -1;
next[0] = -1;
while (j < str.length())
{
if (k == -1 || str[j] == str[k])
{
j++; k++; next[j] = k;
}
else
{
k = next[k];
}
}
}
int kmp(string str1, string str2, int next[])
{
int i = 0, j = 0;
int l1 = str1.length();
int l2 = str2.length();
while (i < l1 && j < l2)
{
if (j == -1 || str1[i] == str2[j])
{
i++;
j++;
}
else
{
j = next[j];
}
}
if (j == str2.length())
return i - j + 1;
else
return 0;
}
int main()
{
int t;
cin >> t;
while (t--)
{
string str1, str2, str3, str = "";
cin >> str1 >> str2 >> str3;
int l = str2.length();
int next[100];
getnext(str2, next);
int temp = kmp(str1, str2, next);
cout << str1 << endl;
if (temp)
{
str = str1.substr(0, temp - 1);
str += str3;
str += str1.substr(temp + l - 1, str1.length());
}
else
str = str1;
cout << str << endl;
}
return 0;
}
D. 串应用- 计算一个串的最长的真前后缀
给定一个串,如ABCDAB,则ABCDAB的真前缀有:{ A, AB,ABC, ABCD, ABCDA }ABCDAB的真后缀有:{ B, AB,DAB, CDAB, BCDAB } 因此,该串的真前缀和真后缀中最长的相等串为AB,我们称之为该串的“最长的真前后缀”。试实现一个函数string matched_Prefix_Postfix(string str),得到输入串str的最长的真前后缀。若不存在最长的真前后缀则输出empty
输入
第1行:串的个数 n第2行到第n+1行:n个字符串
输出
n个最长的真前后缀,若不存在最长的真前后缀则输出empty。
输入:
6
a
ab
abc
abcd
abcda
abcdab
输出:
empty
empty
empty
empty
a
ab
#include<iostream>
#include<string>
using namespace std;
string matched_Prefix_Postfix(string str) {
string ss = "empty";
int len = (int)str.length();
int max = 0;
string s1, s2;
for (int i = 1; i < len; i++) {
s1 = str.substr(0, i);
s2 = str.substr(len-i, len - 1);
if (s1 == s2&&max<i) {
max = i;
ss = s1;
}
}
return ss;
}
int main() {
int n;
string s;
cin >> n;
while (n--) {
cin >> s;
matched_Prefix_Postfix(s);
cout << matched_Prefix_Postfix(s) << endl;
}
}
E. 子串循环问题 (Ver. I)
给定一个字符串,求需要添加至少几个字符到字符串末尾才能使得整个字符串串由某一个不为本身的子串循环构成?
如"abca",添加"bc"后构成"abcabc",其由子串"abc"循环构成;也可以添加"abca"后构成"abcaabca",其由子串"abca"循环构成,相比之下"bc"只有2个字符,添加的字符量最少。
输入
第一行包括一个整数T(1 <= T <= 100),代表测试组数
每组测试数据包括一行字符串,其长度范围为 [3, 10^4]
输出
对于每组测试数据
输出一个整数N,代表添加的最小字符数量
输入:
3
aaa
abca
abcdefg
输出:
0
2
7
//根据next数组的定义来做
#include <iostream>
#include <string>
using namespace std;
int next(string a)
{
string t1, t2;
int len = (int)a.length();
int j = 0;
for (int i = 0; i < len - 1; i++)
{
t1 = a.substr(0, i + 1);
t2 = a.substr(len - 1 - i);
if (t1 == t2 && i + 1 > j)
j = i + 1;
}
return j;
}
int main(void)
{
int i, n;
cin >> n;
for (i = 0; i < n; i++)
{
string a;
cin >> a;
int len = (int)a.length();
int next_len = next(a);
int L = len - next_len;
if (!(len % L) && len != L)
cout << '0' << endl;
else
cout << L - len % L << endl;
}
return 0;
}
F. 可重叠子串 (Ver. I)
给定一个字符串(模式串)和一些待查找的字符串,求每个待查找字符串在模式串中出现的次数(可重叠)
输入
第一行输入t,表示有t组测试数据
每一组测试数据包含多行:
每一组的第一行包括一个字符串P,长度不超过105,且非空串
每一组的第二行包括一个整数N,代表待查找的字符串数量 (1 <= N <= 5)
每一组接下来的N行,每一行包括一个待查找的字符串,其长度不超过50,且非空串
输出
对于每组测试数据,
输出每个待查找字符串出现的次数,
具体输出见样例
输入:
2
aabbcc
3
aa
bb
cc
ababab
1
aba
输出:
aa:1
bb:1
cc:1
aba:2
#include<iostream>
#include<string>
using namespace std;
int time(string s, string ss) {
int time = 0;
int len_s = (int)s.length();
int len_ss = (int)ss.length();
for (int i = 0; i < len_s; i++) {
string sss = s.substr(i, len_ss);
if (ss == sss) time++;
}
return time;
}
int main() {
int n, m;
cin >> n;
string s, ss;
while (n--) {
cin >> s >> m;
while (m--) {
cin >> ss;
cout << ss << ":" << time(s, ss) << endl;
}
}
}