寻找发帖“水王”

Tango 是微软亚洲研究院的一个试验项目。研究院的员工和实习生们都很喜欢在Tango上面交流灌水。传说,Tango 有一大“水王”,他不但喜欢发贴,还会回复其他ID 发的每个帖子。坊间风闻该“水王”发帖数目超过了帖子总数的一半。如果你有一个当前论坛上所有帖子(包括回帖)的列表,其中帖子作者的ID 也在表中,你能快速找出这个传说中的Tango 水王吗?


分析:

如果每次删除两个不同的 ID(不管是否包含“水王”的ID),那么,在剩下的ID 列表中,“水王”ID 出现的次数仍然超过总数的一半。看到这一点之后,就可以通过不断重复这个过程,把ID 列表中的ID 总数降低(转化为更小的问题),从而得到问题的答案。该思路,避免了排序这个耗时的步骤,总的时间复杂度只有O(N),且只需要常数的额外内存。


代码:

Type Find(Type* ID, int N)
{
  Type candidate;
  int nTimes, i;
  for(i = nTimes = 0; i < N; i++)
  {
    if(nTimes == 0)
    {
      candidate = ID[i], nTimes = 1;
    }
    else
    {
      if(candidate == ID[i])
        nTimes++;
      else
        nTimes--;
    }
  }
  return candidate;
}

扩展问题:

如果有3个人的发帖数量都超过1/4.怎么把他们三个都找到.

代码:

Type candidate1;
Type candidate2;
Type candidate3;

void Find(Type* ID, int N)
{
    int nTimes1 = 0;
    int nTimes2 = 0;
    int nTimes3 = 0;

    for(int i = 0; i < N; i++)
    {
        if (nTimes1 == 0)
        {
            candidate1 = ID[i];
            nTimes1 = 1;
        }
        else if (nTimes2 == 0)
        {
            candidate2 = ID[i];
            nTimes2 = 1;
        }
        else if (nTimes3 == 0)
        {
            candidate3 = ID[i];
            nTimes3 = 1;
        }
        else if (nTimes4 == 0)
        {
            candidate4 = ID[i];
            nTimes4 = 1;
        }
        else
        {
            if (candidate1 == ID[i])
                nTimes1++;
            else if (candidate2 == ID[i])
                nTimes2++;
            else if (candidate3 == ID[i])
                nTimes3++;
            else if (candidate4 == ID[i])
                nTimes4++;
            else
            {
                nTimes1--;
                nTimes2--;
                nTimes3--;
            }
        }
    }
}

int main()
{
    int a[] = {0,4,1,4,0,4,1,4,1,0,3,3,0,3,3,3};
    Find(a,16);
    cout << candidate1 <<" " << candidate2 << " " << candidate3 << endl;
    return 0;
}

posted on 2012-09-20 21:10  赛欧拉  阅读(112)  评论(0)    收藏  举报