查找字符串中最常见的字符对

时间:2012-12-20 20:14:21

标签: c string algorithm function

我写了以下函数

//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)?

4 个答案:

答案 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]);

这是link to a demo on ideone

请记住,尽管这是渐近最快的解决方案(即它是O(N),并且你不能使它比O(N)更快),但性能对于较短的字符串来说并不好。事实上,您的解决方案将在短于大约256个字符的输入上击败它,甚至可能更多。您可以对此代码应用许多优化,但我决定不添加它们以保持代码的主要概念以最纯粹和最简单的形式清晰可见。

答案 1 :(得分:4)

如果您想要 O(n)运行时,可以使用hashtable(例如,Java的HashMap

  • 一次性遍历您的字符串,一次1个字符 O(n)
  • 对于每个访问过的角色,请向前看另外一个角色(这是你的角色对 - 只是连接它们) O(1)
  • 对于找到的每个此类字符对,首先在哈希表中查找: O(1)
    • 如果它还没有在哈希表中,请将其添加为字符对作为键,并将int 1作为值(这将计算您在字符串中看到它的次数)。的 O(1)
    • 如果它已经在哈希表中,则增加其值 O(1)
  • 查看完字符串后,检查具有最高计数的对的哈希表。 O(m)(其中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

所以你需要的是一个有效的算法,用于存储和计算与字符对相关的数量并找到最常见的算法。