• 编程之美——发帖水王


    题目:

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

    分析:

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

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

    如果一个ID出现的次数超过总数的一半。那么,无论水王的ID是什么,这个有序的ID列表中的第N/2项(从0开始编号)一定会是这个ID。不必再次扫描列表。如果能够迅速定位到列表的某一项,除去排序的时间复杂度,后处理的需要的时间为O(1)。

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

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

    public static int FindKingID (int [] ID,int N)
        {
            int BlogKing = 0;
            int nTimes,i;
            
            for(i = nTimes= 0;i<N;i++)
            {
                if(nTimes == 0)
                {
                    BlogKing = ID[i];
                    nTimes = 1;
                }
                else
                {
                    if(BlogKing == ID[i])
                    {
                        nTimes++;
                    }
                    else {
                        nTimes--;
                    }
                }
            }
            return BlogKing;
        }

    这个题目体现了计算机科学中很普遍的思想,就是如何把一个问题转化成规模较小的若干子问题。分治、递推和贪心都是基于这样的思路。在转化过程中,小问题跟原问题的本质上一致。同样我们可以将小问题转化为更小的问题。因此,转化过程是很重要的。像上面的这个题目,我们保证了问题的解在小问题中仍然具有与原问题相同的性质:

    水王的ID在ID列表中的数量超过一半。转化的效率越高,转化之后问题规模缩小的越快,则整体的时间复杂度越低。

  • 相关阅读:
    Rraspberry Pi 4B python3 安装opencv
    如何用arduion制作智能 垃圾桶
    MySQL(二)表结构的管理
    MySQL(一)基础操作
    vc++绘图基础
    网站签~
    (转)Oracle 知识日常积累
    利用反射判断bean属性不为空(null和空串)
    (转)Oracle 单字段拆分成多行
    svn 解决树冲突
  • 原文地址:https://www.cnblogs.com/Jiaoxia/p/3986222.html
Copyright © 2020-2023  润新知