问题 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
提示
为什么next值和课本的不一样???
AC代码
#include<bits/stdc++.h>
using namespace std;
class myString {
string mainstr;
void GetNext(string p, int next[]);
int KMPFind(string p, int pos, int next[]);
public:
myString() { cin >> mainstr; }
int KMPFindSubstr(string p, int pos);
};
void myString::GetNext(string p, int next[]) {
int m = p.length();
next[0] = -1;
int j = 0, k = -1;
while (j < m - 1)
{
if (-1 == k || p[k] == p[j])
{
k += 1;
j += 1;
next[j] = k;
}
else k = next[k];
}
}
int myString::KMPFind(string p, int pos, int next[]) {
int i = pos, j = 0;
int m = mainstr.length(), n = p.length();
while (i < m && j < n)
{
if (-1 == j || mainstr[i] == p[j])
{
i++; j++;
}
else j = next[j];
}
if (j >= n)
return i - n;
return -1;
}
int myString::KMPFindSubstr(string p, int pos)
{
int* next = new int[p.length()];
GetNext(p, next);
for (int i = 0; i < p.length(); i++)
cout << next[i] << " ";
cout << endl;
int v = KMPFind(p, pos, next);
delete[]next;
return v + 1;
}
int main() {
int n;
cin >> n;
while (n--)
{
myString s;
string t;
cin >> t;
cout << s.KMPFindSubstr(t, 0) << endl;
}
return 0;
}
问题 B: 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
AC代码
#include<bits/stdc++.h>
using namespace std;
class myString {
string mainstr;
void GetNext(string p, int next[]);
int KMPFind(string p, int pos, int next[]);
public:
myString() { cin >> mainstr; }
int KMPFindSubstr(string p, int pos);
void display() { cout << mainstr << endl; }
string replace(string old_string, string new_string);
};
void myString::GetNext(string p, int next[]) {
int m = p.length();
next[0] = -1;
int j = 0, k = -1;
while (j < m - 1)
{
if (-1 == k || p[k] == p[j])
{
k += 1;
j += 1;
next[j] = k;
}
else k = next[k];
}
}
int myString::KMPFind(string p, int pos, int next[]) {
int i = pos, j = 0;
int m = mainstr.length(), n = p.length();
while (i < m && j < n)
{
if (-1 == j || mainstr[i] == p[j])
{
i++; j++;
}
else j = next[j];
}
if (j >= n)
return i - n;
return -1;
}
int myString::KMPFindSubstr(string p, int pos)
{
int* next = new int[p.length()];
GetNext(p, next);
//for (int i = 0; i < p.length(); i++)
//cout << next[i] << " ";
//cout << endl;
int v = KMPFind(p, pos, next);
delete[]next;
//return v + 1;
return v;
}
string myString::replace(string old_string, string new_string)
{
int n = KMPFindSubstr(old_string, 0);
if (n == -1)
return mainstr;
string str = mainstr.substr(0, n);
str += new_string;
str += mainstr.substr(n + old_string.length());
return str;
}
int main() {
int n;
cin >> n;
while (n--)
{
myString s;
s.display();
string old,_new;
cin >> old >> _new;
cout << s.replace(old, _new) << endl;
/*cout << s.KMPFindSubstr(t, 0) << endl;*/
}
return 0;
}
问题 C: 串应用- 计算一个串的最长的真前后缀
题目描述
给定一个串,如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
AC代码
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
string matched_Prefix_Postfix(string str)
{
if (str.length() == 1)
return "ERROR";
int cnt = str.length() - 1;
string s = str;
reverse(s.begin(), s.end());
while (cnt >= 1)
{
string temp = s.substr(0, cnt);
reverse(temp.begin(), temp.end());
if (temp == str.substr(0,cnt))
return temp;
cnt--;
}
return "ERROR";
}
int main() {
int n;
cin >> n;
while (n--)
{
string s;
cin >> s;
s = matched_Prefix_Postfix(s);
if (s == "ERROR")
cout << "empty" << endl;
else
cout << s << endl;
}
return 0;
}
问题 D: DS串应用—最长重复子串
题目描述
求串的最长重复子串长度(子串不重叠)。例如:abcaefabcabc的最长重复子串是串abca,长度为4。
输入
测试次数t
t个测试串
输出
对每个测试串,输出最长重复子串长度,若没有重复子串,输出-1.
样例输入
3
abcaefabcabc
szu0123szu
szuabcefg
样例输出
4
3
-1
AC代码
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
int main() {
int n;
cin >> n;
while (n--)
{
string s;
cin >> s;
int _max = -1;
for (int i = 0; i < s.length(); i++)
for (int j = 1; j <= s.length(); j++)
{
string str = s.substr(i, j);
int pos = s.find(str, i + str.length());
if (pos == string::npos)
continue;
if (_max < (int)str.length())
_max = str.length();
}
cout << _max << endl;
}
return 0;
}
问题 E: 子串循环问题 (Ver. I)
题目描述
给定一个字符串,求需要添加至少几个字符到字符串末尾才能使得整个字符串串由某一个不为本身的子串循环构成?
如"abca",添加"bc"后构成"abcabc",其由子串"abc"循环构成;也可以添加"abca"后构成"abcaabca",其由子串"abca"循环构成,相比之下"bc"只有2个字符,添加的字符量最少。
输入
第一行包括一个整数T(1 <= T <= 100),代表测试组数
每组测试数据包括一行字符串,其长度范围为 [3, 104]
输出
对于每组测试数据
输出一个整数N,代表添加的最小字符数量
样例输入
3
aaa
abca
abcdefg
样例输出
0
2
7
AC代码
#include<iostream>
using namespace std;
int* getNext(string s);
int main()
{
int t;
cin >> t;
while (t--)
{
string s;
cin >> s;
int* next = getNext(s);
int len = s.size();
int circle_len = len - next[len];
int add_len;
if (circle_len != len && len % circle_len == 0)
add_len = 0;
else
add_len = circle_len - len % circle_len;
cout << add_len << endl;
}
return 0;
}
int* getNext(string s)
{
int j = 0, i = -1;
int* next = new int[s.length() + 1];
next[0] = -1;
while (j < s.length())
{
if (-1 == i || s[i] == s[j])
{
j++;
i++;
next[j] = i;
}
else
i = next[i];
}
return next;
}