代码改变世界

寻找发帖水王

2013-06-09 21:18  夜与周公  阅读(292)  评论(0编辑  收藏  举报

  在<<编程之美>>这本书中提到了发帖水王的问题。

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

  扩展版本:随着Tango的发展,管理员发现,“超级水王”没有了。统计结果表明,有3个发帖很多的ID,他们的发帖数目都超过了帖子总数目N的1/4。你能从发帖ID列表中快速找出他们的ID吗?

  先看原始问题,假设ID序列是已经排序好的,序列的长度为N,那么第2/N个元素一定是我们需要找的那个元素,算法时间复杂度O(1)。然而,若是未排序的,那么算法排序的时间复杂度O(N*logN)。很显然,对于这个问题,如果只用用排序方法解决,那就没有多大的存在价值,因此,需要进一步的思考当前问题。实际上,如果我们在序列中删除两个不同的元素,我们需要寻找的“水王”,仍然存在于余下的序列当中,但问题的规模已经被我们简化(适合算法设计思想中的分治与递归)。

#include <iostream>

using namespace std;

typedef int Find_Type;

Find_Type find_type(int* array, int N)
{
    Find_Type candinate;
    int nTimes=0;
    for (int i=0; i != N; i++)
    {
        if ( 0 == nTimes)
        {
            candinate = array[i];
            nTimes++;
        }
        else
        {
            if (array[i] == candinate)
            {
                nTimes++;
            }
            else
            {
                nTimes--;
            }

        }
    
    }
    return candinate;
}
int main()
{
    int array[] = {1,2,2,2,3,4,2,2,5};
    Find_Type candinate = find_type(array, sizeof(array)/ sizeof(int));
    cout<<candinate;
    system("pause");
    return 0;
}

   拓展版本类似与原问题,将三个ID看出一个整体,解决思路与第一个相似,不同的是的需要保存三个nTimes。在遍历过程中,当前ID不同与保存的三个ID,若某个ID的nTimes等于0,则用当前ID替换掉该ID,若不存在,则将三个ID的nTimes均减1。

#include <iostream>

using namespace std;

typedef int Find_Type;

Find_Type* find_3type(int* array, int N)
{
    const int cand_num = 3;
    Find_Type *cand_list = new Find_Type[cand_num];
    int nTimes[cand_num] = {0};
    for (int i = 0; i != cand_num; i++)
    {
        cand_list[i] = -1;
    }

    for (int i = 0; i != N; i++)
    {
        int currentID = array[i];
        int tag = -1;

        for (int i = 0; i != cand_num; i++)   //判断当前的ID与保存的三个ID某个ID相同, -1表示不存在
        {
            if (currentID == cand_list[i])
            {
                tag = i;
                break;
            }
        }

        if (-1 == tag)               //当前ID与保存的三个ID均不同
        {
            int j=0;
            for (; j != cand_num; j++)
            {
                if (0 == nTimes[j])  //如果三个ID中,某个ID的nTime等于0,则将当前ID赋值给该ID,其nTime赋值1
                {
                    cand_list[j] = currentID;
                    nTimes[j] = 1;
                    break;
                }
            }
            if (j == cand_num)       //如果三个ID均不存在nTime等于0的,则将三个ID的nTime减1
            {
                for (int k = 0; k != cand_num; k++)
                {
                    nTimes[k]--;
                }
            }
        }
        else                         //当前ID与保存的某个ID相同,则该ID的nTimes加1
        {
            nTimes[tag]++;
        }
    }
    return cand_list;
}

int main()
{
    int array[] = {1,2,2,3,4,2,2,3,3,4,4};
    int cand_num =3;
    Find_Type* cand_list = find_3type(array,sizeof(array) / sizeof(int));
    for (int i = 0; i != cand_num; i++)
        cout<<cand_list[i]<<"\t";
    system("pause");
    return 0;
}