gpt4 book ai didi

c++ - 最长最大重复子串

转载 作者:搜寻专家 更新时间:2023-10-30 23:53:46 29 4
gpt4 key购买 nike

子串的长度可以是 1,2,3...我试图解决的问题涉及找到出现次数最多的子字符串。所以它基本上分解为找到具有最大频率的字符。但是,我发现我可以在 O(n) 中使用后缀树找到最长的重复子串。但是,后缀树返回保持长度优先的子串。我想找到出现次数最多的子串,并且在这些子串中我想找到最长的一个。例如:

In the following string: ABCZLMNABCZLMNABC
A suffix tree will return ABCZLMN as the longest repeating substring.
However, what I am looking for is ABC; as it is the longest out of all the ones having frequency = 3.

我尝试通过在两个索引 i 和 j 之间生成子字符串来解决这个问题。之后,使用在 O(n) 中运行的 Z 算法在每种情况下找到这些子串的出现。然而总的复杂度是 O(n^3)

我的 O(n^3) 代码

map<ll,vector<string>> m;
string s; cin >> s;
for(ll i=0;i<s.length();i++){
string c;
for(ll len=0; i+len<s.length();len++){
c+=s[i+len];
ll z[N];
ll l=0,r=0;
string kk;
for(ll p=0;p<c.length();p++){
kk+=c[p];
}
kk+="#";
for(ll p=0;p<s.length();p++){
kk+=s[p];
}
for(ll k=1;k<kk.length();k++){
if(k>r){
l=r=k;
while(r<c.length()&&kk[r-l]==kk[r])r++;
z[k]=r-l;
r--;
}
else{
ll m=k-l;
if(z[m]<r-k+l)z[k]=z[m];
else{
l=k;
while(r<c.length()&&kk[r-l]==kk[r])r++;
z[k]=r-l;
r--;
}
}
}
ll occ=0;
for(ll n=0;n<kk.length();n++){
if(z[n]==c.length())occ++;
}
m[occ].push_back(c);
}
}

我找不到合适的解决方案来提高效率。请帮忙。谢谢。

最佳答案

单个字符算作一个子字符串,因此最大重复子字符串的出现频率必须等于字符串中最常见的字符。

其中的一个含义是,最大重复子串中的每个字符只能在字符串中出现一次,因为如果它出现不止一次,那么该字符本身将成为最大重复字符串。例如子串“dad”在字符串“dadxdadydadzdadydad”中出现了5次,而子串“d”出现了10次。

它们也必须每次都以相同的顺序出现(否则单个字符的出现频率将高于子字符串,并且它们本身就是最大的重复子字符串)。它们也不能单独出现在子字符串中(否则它们将再次成为最大重复子字符串)。

因此,最大重复子串必须由同样最常出现的字符的子集(或所有)组成。

我们可以很容易地通过遍历字符串并计算它们来找出这些是哪些字符。我们还可以推断出哪些字符以何种顺序出现,方法是跟踪每个字符前后出现的字符,如果每次都相同则存储该字符,否则为零。例如,在字符串“abcxabcyabczabcyabc”中,字符“b”总是在“a”之前,在“c”之后:

string s; cin >> s;
int i, freq[256];
char prev[256], next[256];
for(i = 1; i < 256; i++)
freq[i] = prev[i] = next[i] = 0;
int maxFreq = 0;
for(i = 0; i < s.length(); i++)
{
char c = s[i];
char p = (i == 0) ? 0 : s[i-1];
char n = (i < s.length() - 1) ? s[i+1] : 0;
if(freq[c] == 0) // first time to encounter this character
{
prev[c] = p;
next[c] = n;
}
else // check if it is always preceded and followed by the same characters:
{
if(prev[c] != p)
prev[c] = 0;
if(next[c] != n)
next[c] = 0;
}
// increment frequency and track the maximum:
if(++freq[c] > maxFreq)
maxFreq = freq[c];
}

if(maxFreq == 0)
return 0;

然后,我们可以遍历每个字符以及频率等于最大频率的字符,找到我们可以按照 next 字符索引从该字符开始形成的字符串长度:

int maxLen = 0;
int startingChar = 0;
for(i = 1; i < 256; i++)
{
// should have a frequency equal to the max and not be preceded
// by the same character each time (or it is in the middle of the string)
if((freq[i] == maxFreq) && (prev[i] == 0))
{
int len = 1, j = i;
while(next[j] != 0)
{
len++;
j = next[j];
}
if(len > maxLen)
{
maxLen = len;
startingChar = i;
}
}
}

一旦我们找到了最大重复子串,打印出来:

// print out the maximum length string:
int j = startingChar;
while(j != 0)
{
cout << (char)j;
j = next[j];
}
cout << endl;

如果您不喜欢迭代这些固定大小的数组或需要支持 UNICODE 字符等,您可以使用 map 从字符类型到包含字符频率以及上一个和下一个字符的结构.

关于c++ - 最长最大重复子串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38372159/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com