zoukankan      html  css  js  c++  java
  • 【编程之美学习笔记】2.3寻找发帖水王

    003E5CD0坊间风闻“水王”发帖数目超过帖子总数的一半,如果你有一个当前论坛上所有帖子的列表,其中帖子作者的ID也在表中,你能快速找出这个传说中的水王吗?

    题意即找出数组中超过一半的数

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

    但事实上,若ID列表有序,不必再次扫描列表。若一个ID出现的次数超过总数N的一半,那么这个有序的ID列表中的第N/2项(从0开始编号)一定会是这个ID。这样能迅速定位到列表的某一项的话(比如用数组),该时间复杂度为O(N * log2N )。

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

    如果每次删除 2 个不同的ID(不管是否包含“水王”的ID),那么在剩下的ID列表中,“水王”的ID出现的次数仍然超过总数的一半。可以通过不断重复这个过程把ID列表中的ID总数降低(转化为更小的问题),从而得到答案。

    这个思路,避免了排序这个耗时的步骤,总的时间复杂度只有O(N),且只需要常数的额外内存。

     1 Type Find(Type *ID, int N){
     2     Type candidate;
     3     int nTimes, i;
     4     for(i = nTimes = 0; i < N; i++){
     5         if(nTimes == 0){
     6             candidate = ID[i], nTimes = 1;
     7         }
     8         else{
     9             if(candidate == ID[i])
    10                 nTimes++;
    11             else
    12                 nTimes--;
    13         }
    14     }
    15     return candidate;
    16 }
    View Code

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

    扩展问题

    现在有3个发帖很多的ID,他们的发帖数目都超过了帖子总数目N的1/4,你能从发帖ID列表中快速找出他们的ID吗?

    思路与本题一样用抵消法,每次删除 4 个不同的ID即可。

     1 Type candidate[3];
     2 void Find1(Type *ID, int N) {
     3     int nTimes[3] = {0};
     4     for(int i = 0; i < N; ++i) {
     5         if(nTimes[0] == 0) {
     6             candidate[0] = ID[i];
     7             nTimes[0] = 1;
     8         }else if(nTimes[1] == 0 && ID[i] != candidate[0]) {
     9             candidate[1] = ID[i];
    10             nTimes[1] = 1;
    11         }else if(nTimes[2] == 0 && ID[i] != candidate[0] && ID[i] != candidate[1]) {
    12             candidate[2] = ID[i];
    13             nTimes[2] = 1;
    14         }else{
    15             if(candidate[0] == ID[i])
    16                 nTimes[0]++;
    17             else if(candidate[1] == ID[i])
    18                 nTimes[1]++;
    19             else if(candidate[2] == ID[i])
    20                 nTimes[2]++;
    21             else{
    22                 nTimes[0]--;
    23                 nTimes[1]--;
    24                 nTimes[2]--;
    25             }
    26         }
    27     }
    28 }
    View Code
  • 相关阅读:
    mysql orderby 查询过慢优化
    js密码复杂度验证
    下载linux指定目录下的文件
    关于对接农业银行支付的问题
    string拼接时去掉最后一个逗号
    java基础题整理(1)
    springboot 读取 resource文件
    自动生成Excel 报表工具类
    java设计模式—— 工厂模式
    pyqt线程实现
  • 原文地址:https://www.cnblogs.com/GraceSkyer/p/5843555.html
Copyright © 2011-2022 走看看