求串的第一个最长重复子串的下标和长度

/*
采用顺序结构存储串,编写一个程序,求串s中出现的第一个最长重复子串的下标和长度。


1.读取串
2.求后缀数组
3.字典序排序所有后缀
4.求相邻后缀最长子串
5.比较本次结果与上次结果,取最大
*/


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


using namespace std;


typedef vector<string>::iterator ITER;//从定义类型


class max_substr
{
public:
max_substr(){}


~max_substr(){}

//文件读入串
void getstr(string name)
{
ifstream readfile;
readfile.open(name, ios::in);
if (readfile.is_open())//是否打开
{
getline(readfile, s);//读取一行
cout << s << endl;
}
readfile.close();
}


void solve()
{
int temp, max;
string t, max_t;


//得到后缀数组
for (size_t i = 0; i<s.size(); ++i)
{
t = s.substr(i, s.size());//求后缀
behind.push_back(t);
rank.insert(pair<string, int>(t, i));//存储后缀及其首字符下标
}
stable_sort(behind.begin(), behind.end());//按字典序排序,默认为从小到大
max = -1;
//迭代比较相邻两后缀
for (iter = behind.begin(); *iter != behind.back(); ++iter)
{
temp = MaxPrefix(iter, iter + 1);//取最长子串尾字符下标
if (temp>max)//与前一个比较,取最长
{
max = temp;
max_i = iter;
}
}


for (int i = 0; i<max; ++i)//取出重复串
max_t += (*max_i)[i];
cout << "长度为:" << max << endl;
cout << "下标为:" << rank[max_t] << endl;
cout << max_t << endl;
}


private:
string s;
vector<string> behind;//后缀数组
map<string, int> rank;//关联容器
ITER iter, max_i;//迭代/保存字符地址位置


//得到相邻两串最长公共字符子串尾下标
int MaxPrefix(ITER s1, ITER s2)
{
int i = 0;
while (!(*s1).empty() && (*s1)[i] == (*s2)[i])//当前字符相等比较下一位
{
++i;
}
return i;
}
};


int main()
{
max_substr str;
str.getstr("data");
str.solve();
return 0;
}


测试结果



  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 我建议使用双指针法,从头到尾遍历一次字符S,分别用两个指针指向字符的开头和结尾,如果两个指针指向的字符相同,则移动结尾指针,如果不相同,则比较当前最长的等值子串和当前遍历的子串,如果比当前最长的等值子串长,则更新最长的等值子串,移动开头指针,继续遍历,最后输出最长的等值子串。 ### 回答2: 算法思路: 1. 定义一个变量max_length来记录最大等值子串长度,初始值为1。 2. 定义一个变量start来记录最大等值子串的起始位置,初始值为0。 3. 定义一个变量current_length来记录当前等值子串长度,初始值为1。 4. 遍历字符S,从第二个字符开始: - 如果当前字符与前一个字符相同,则当前等值子串长度加1; - 如果当前字符与前一个字符不同,则表示当前等值子串结束,将当前等值子串长度与max_length进行比较: - 如果当前等值子串长度大于max_length,则更新max_length和start的值; - 将current_length重置为1,表示开始一个新的等值子串。 5. 遍历结束后,根据max_length的值判断是否存在等值子串: - 如果max_length大于1,表示存在等值子串,则输出最大等值子串长度和起始位置; - 如果max_length等于1,表示不存在等值子串,则输出相应的信息。 C++代码实现: ```cpp #include<iostream> #include<string> using namespace std; void findMaxEqualSubstring(string S) { int max_length = 1; int start = 0; int current_length = 1; for (int i = 1; i < S.length(); i++) { if (S[i] == S[i - 1]) { current_length++; } else { if (current_length > max_length) { max_length = current_length; start = i - max_length; } current_length = 1; } } if (max_length > 1) { cout << "最大等值子串长度为:" << max_length << endl; cout << "最大等值子串的起始位置为:" << start << endl; } else { cout << "不存在等值子串" << endl; } } int main() { string S; cout << "请输入字符S:"; cin >> S; findMaxEqualSubstring(S); return 0; } ``` 注意:以上代码,我们将起始位置start定义为最大等值子串的起始位置减1,因为题目要求的是输出其起始位置,而数组的下标是从0开始的。 ### 回答3: 算法的思路如下: 1. 首先判断S的长度是否小于等于1,如果是,则输出信息"不存在等值子串",并结束算法。 2. 设立两个指针i和j,分别指向子串的起始位置和结束位置。初始化i=0,j=1。 3. 从位置i开始,依次遍历字符S的字符,同时判断当前字符与下一个字符是否相等。如果相等,则将指针j移动到下一个位置,继续判断下一个字符是否相等。如果不相等,则将当前子串长度与记录的最大长度进行比较,如果大于最大长度,则更新最大长度,并更新最长等值子串的起始位置和结束位置。 4. 继续向后遍历,直到遍历完整个S。 5. 最后根据记录的最长等值子串的起始位置和结束位置,输出最长等值子串。 以下是算法的具体实现: ```c++ #include <iostream> #include <string> using namespace std; void findLongestEqualSubstr(string S) { int len = S.length(); if (len <= 1) { cout << "不存在等值子串" << endl; return; } int maxLen = 0; int start = 0, end = 0; int i = 0, j = 1; while (j < len) { if (S[i] == S[j]) { j++; } else { int currentLen = j - i; if (currentLen > maxLen) { maxLen = currentLen; start = i; end = j - 1; } i = j; j = i + 1; } } int currentLen = j - i; if (currentLen > maxLen) { maxLen = currentLen; start = i; end = j - 1; } if (maxLen <= 1) { cout << "不存在等值子串" << endl; } else { cout << "最长等值子串为:" << S.substr(start, maxLen) << endl; } } int main() { string S = "aabbbbcccccdd"; findLongestEqualSubstr(S); return 0; } ``` 以上代码以字符S = "aabbbbcccccdd" 为例进行了测试,输出结果为:"最长等值子串为:ccccc"。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值