我写了以下函数
//O(n^2)
void MostCommonPair(char * cArr , char * ch1 , char * ch2 , int * amount)
{
int count , max = 0;
char cCurrent , cCurrent2;
int i = 0 , j;
while(*(cArr + i + 1) != '\0')
{
cCurrent = *(cArr + i);
cCurrent2 = *(cArr + i + 1);
for(j = i , count = 0 ; *(cArr + j + 1) != '\0' ; j++)
{
if(cCurrent == *(cArr + j) && cCurrent2 == *(cArr + j + 1))
{
count++;
}
}
if(count > max)
{
*ch1 = cCurrent;
*ch2 = cCurrent2;
max = *amount = count;
}
i++;
}
}
以下输入
“xdshahaalohalobscxbsbsbs”
ch1 = b ch2 = s amount = 4
但是在我看来这个函数非常无效,有没有办法只通过字符串一次或将运行大小减少到O(n)?
答案 0 :(得分:5)
由于char
最多可以容纳256个值,因此可以设置[256 * 256]个计数器的二维表,在字符串中运行一次,递增与每对字符对应的计数器字符串。然后你可以浏览256x256数字表,选择最大数量,并通过查看它在2D数组中的位置来了解它所属的对。由于计数器表的大小固定为与字符串长度无关的常量值,因此该操作为O(1)
,即使它需要两个嵌套循环。
int count[256][256];
memset(count, 0, sizeof(count));
const char *str = "xdshahaalohalobscxbsbsbs";
for (const char *p = str ; *(p+1) ; p++) {
count[(int)*p][(int)*(p+1)]++;
}
int bestA = 0, bestB = 0;
for (int i = 0 ; i != 256 ; i++) {
for (int j = 0 ; j != 256 ; j++) {
if (count[i][j] > count[bestA][bestB]) {
bestA = i;
bestB = j;
}
}
}
printf("'%c%c' : %d times\n", bestA, bestB, count[bestA][bestB]);
请记住,尽管这是渐近最快的解决方案(即它是O(N)
,并且你不能使它比O(N)
更快),但性能对于较短的字符串来说并不好。事实上,您的解决方案将在短于大约256个字符的输入上击败它,甚至可能更多。您可以对此代码应用许多优化,但我决定不添加它们以保持代码的主要概念以最纯粹和最简单的形式清晰可见。
答案 1 :(得分:4)
如果您想要 O(n)运行时,可以使用hashtable(例如,Java的HashMap)
int 1
作为值(这将计算您在字符串中看到它的次数)。的 O(1)强> m
是可能配对的数量;必须m <= n
答案 2 :(得分:1)
是的,您可以通过保持运行计数在近似线性的时间内完成此操作。
这有帮助吗?
答案 3 :(得分:0)
假设大多数“普通对”是指最常见的两个连续字符集
在伪代码级别,你想要
Read the first character into the "second character" register
while(there is data)
store the old second character as the new first character
read the next character as the second one
increment the count associated with this pair
Select the most common pair
所以你需要的是一个有效的算法,用于存储和计算与字符对相关的数量并找到最常见的算法。