我想在C ++中找到字符串中所有子串的频率。目前我正在使用以下内容:
unordered_map<string,int> mp;
string s;// the string of which we want all substrings... n is length
cin>>s;
string t;
for(int i=0,i<=n-1;++i) // starting point of a substring
{
t="";
for(int j=i;j<=n-1;++j) // all substrings startings at i
{
t+=s[j];
++mp[t];
}
}
我想提高它的时间复杂度。我们可以做得更好吗?是否存在更好的算法?对不起,如果这里不是主题...如果是这样的话,我会关闭它。
修改:
这就是我想出的......保持字符串的所有后缀的trie。然后遍历从i开始的所有子串,以便搜索为O(1)。
每个节点指定一个子字符串(后缀的前缀)。现在保持每个节点的频率并相应地更新它。虽然这个方法是O(n ^ 2)但是由于内存分配和将节点的每个下一个指针(26次)重置为NULL,常量相当大。我可以进一步优化它吗?还可以有更快的替代方式来存储trie而不是链表吗?我能够挤出我的解决方案,但它非常接近时限。
答案 0 :(得分:0)
以这种方式思考。想象一下,你的字符串长10个字符,所有字符都不同:
`0123456789`
在这种情况下,所有子串都是唯一的。所以有O(n ^ 2)个唯一的子串。每个子字符串在字典中都需要自己的条目。确切地说,在这种情况下,(n ^ 2)/ 2 = 50个条目。
因此,在字典中插入这些子字符串至少需要50次插入操作。
当然,在一般情况下,为避免O(n ^ 2)的上限,可以做的并不多。
专注于使代码本身更快 - 我不确定您是否会找到更好的算法。
答案 1 :(得分:0)
这是原始C代码中的一个版本。它使用两个与输入字符串(s_len
)长度相同的数组来计算匹配数和重复项的位置。优点是字符串永远不会在地图中重复,并且它节省了创建地图条目所需的时间(您发现它的速度要慢得多)。另一个优点是它不需要n ^ 2个存储器,它像map / reduce函数一样立即打印出信息,以便在后面的步骤中处理。它使用本地C内存函数,如calloc()
,bzero()
和memcmp()
来进行有效的内存分配,归零和比较。
算法的工作原理如下:
len
的字符串,len
从1变为s_len
- 1:matches
和dups
; i
)从开头(位置0)到结尾:j
= i+1
至stop
),请将其与当前位置进行比较; i
的匹配数,并将位置j
标记为重复; len
的匹配数。以下是代码:
#include <stdio.h>
#include <stdlib.h> /* for calloc() */
#include <strings.h> /* for bzero() */
/* Find the number of matching substrings in the string s */
void sub(char *s)
{
size_t s_len = strlen(s);
short *matches = (short *) calloc(s_len, sizeof(short));
short *dups = (short *) calloc(s_len, sizeof(short));
size_t n = s_len * sizeof(short); /* used by bzero() */
size_t len, i, j, stop;
/* Find all substrings of length 1..s_len */
for (len=1; len<s_len; ++len)
{
bzero((void *) matches, n); /* zero out the number of matches */
bzero((void *) dups, n); /* zero out the duplicates */
stop = s_len - len + 1;
for (i=0; i<stop; ++i)
{
if (dups[i]) /* this is a duplicate (was already counted) */
continue;
for (j=i+1; j<stop; ++j)
{
if (memcmp(s+i, s+j, len)) /* substring comparison */
continue; /* not a match? continue */
matches[i]++;
dups[j] = 1;
}
if (matches[i])
printf("%d: %.*s\n", matches[i]+1, (int) len, s+i);
}
}
}
int main()
{
sub("abcabcabcabc");
return 0;
}
这是输出:
4: a
4: b
4: c
4: ab
4: bc
3: ca
4: abc
3: bca
3: cab
3: abca
3: bcab
3: cabc
3: abcab
3: bcabc
2: cabca
3: abcabc
2: bcabca
2: cabcab
2: abcabca
2: bcabcab
2: cabcabc
2: abcabcab
2: bcabcabc
2: abcabcabc