zoukankan      html  css  js  c++  java
  • 寻找发帖“水王”《编程之美》笔记

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

    分析与解法

    首先想到的是一个最直接的方法,我们可以对所有ID进行排序。然后再扫描一遍排好序的ID列表,统计各个ID出现的次数。如果某个ID出现的次数超过总数的一半,那么就输出这个ID。这个算法的时间复杂度为ON * log2N + N)。

    如果ID列表已经是有序的,还需要扫描一遍整个列表来统计各个ID出现的次数吗?

    如果一个ID出现的次数超过总数N的一半。那么,无论水王的ID是什么,这个有序的ID列表中的第N/2项(从0开始编号)一定会是这个ID(读者可以试着证明一下)。省去重新扫描一遍列表,可以节省一点算法耗费的时间。如果能够迅速定位到列表的某一项(比如使用数组来存储列表),除去排序的时间复杂度,后处理需要的时间为O(1)。

    但上面两种方法都需要先对ID列表进行排序,时间复杂度方面没有本质的改进。能否避免排序呢?

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

    代码清单2-8

    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;
    }

    在 这个题目中,有一个计算机科学中很普遍的思想,就是如何把一个问题转化为规模较小的若干个问题。分治、递推和贪心等都是基于这样的思路。在转化过程中,小 的问题跟原问题本质上一致。这样,我们可以通过同样的方式将小问题转化为更小的问题。因此,转化过程是很重要的。像上面这个题目,我们保证了问题的解在小 问题中仍然具有与原问题相同的性质:水王的ID在ID列表中的次数超过一半。转化本身计算的效率越高,转化之后问题规模缩小得越快,则整体算法的时间复杂 度越低。

    扩展问题

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

    参考上面的解法,思路如下:
    如果每次删除四个不同的ID(不管是否包含发帖数目超过总数1/4的ID),那么,在剩下的ID列表中,原先发帖比例大于1/4的ID所占比例仍然大于1/4。可以通过不断重复这个过程,把ID列表中的ID总数降低(转化为更小的问题),从而得到问题的答案。

    代码如下:

    void Find(Type* ID, int N,Type candidate[3])
    {
        Type ID_NULL;//定义一个不存在的ID
        int nTimes[3], i;
        nTimes[0]=nTimes[1]=nTimes[2]=0;
        candidate[0]=candidate[1]=candidate[2]=ID_NULL;
        for(i = 0; i < N; i++)
        {
            if(ID[i]==candidate[0])
            {
                 nTimes[0]++;
            }
            else if(ID[i]==candidate[1])
            {
                 nTimes[1]++;
            }
            else if(ID[i]==candidate[2])
            {
                 nTimes[2]++;
            }
            else if(nTimes[0]==0)
            {
                 nTimes[0]=1;
                 candidate[0]=ID[i];
            }
            else if(nTimes[1]==0)
            {
                 nTimes[1]=1;
                 candidate[1]=ID[i];
            }

            else if(nTimes[2]==0)
            {
                 nTimes[2]=1;
                 candidate[2]=ID[i];
            }

            else
            {
                 nTimes[0]--;
                 nTimes[1]--;
                 nTimes[2]--;
             }
        }
        return;
    }

  • 相关阅读:
    NOI AC#62 color(树上操作)
    fenbi
    bert 压缩优化方向的论文
    bert 编程入门| bert 瘦身技巧
    行政法+刑法+民法
    Bert原理 | Bert油管视频学习法
    vscode的使用以及快捷键总结
    NG课程笔记学习记录
    古典文学+古曲+四大文明古国
    中国地理+地球上的水和大气
  • 原文地址:https://www.cnblogs.com/end/p/2413210.html
Copyright © 2011-2022 走看看