现在的位置: 首页 > 综合 > 正文

编程之美-2.3-寻找发帖“水王”

2018年05月02日 ⁄ 综合 ⁄ 共 1068字 ⁄ 字号 评论关闭

题目:寻找一个ID列表中,有一个ID超过了总数的一半,找出这个ID

分析:

可以对ID进行排序,因为需要寻找的ID超过了一半,所以该ID列表ID[N]中,ID[N/2]一定是这个ID值。复杂度为O(NlgN+1),如果用排序这种方法解决的话,复杂度应该就维持在这个水平,不会降低。再思考一下,难道一定需要排序吗,针对这个问题,我们只是想找出ID数量超过一半的那个唯一的ID。如果每次删除两个不同的ID,那么数量超过一半的那个ID在剩下的ID列表中总会维持超过一半的数量,最后剩下的就一定是该ID。

/*寻找发帖水王,算法有些类似于寻找最大和子序列*/
Type FInd(Type * ID, int N){
    Type candicate;
    int i, nTimes;  //nTimes用来记录重复次数
    for(i = nTimes = 0; i < N; i ++){
        if(nTimes == 0){
            candicate = ID[i];                   //如果发现nTimes=0,则前面的重复完全抵消,重新选择一个candicate 
            nTimes = 1;
        }else {
            if(candicate == ID[i]) nTimes ++;    //如果发现相同ID,重复次数加1 
            else nTimes --;                      //否则减少 
        }
    }
    return candicate;
}
      

扩展问题:

“超级水王”没有了,有3个ID发帖也很多,每个人都超过帖子总数的1/4了,怎么快速找到这三个ID?

思路和“超级水王”的是一样的,只是这次需要有三个candicate[3],和三个nTimes[3]。如果找到与这三个ID相同的,则对应的加1,如果都不相同,则三个ID数量都要减1

/*寻找发帖水王,算法有些类似于寻找最大和子序列*/
Type *Find(Type * ID, int N){
    Type candicate[3];
    int i, j, k, nTimes[3];  //nTimes用来记录重复次数
    for(i = 0; i < 3; i++) nTimes[i] = 0;
    for(i = 0; i < N; i ++){        
        for(j = 0; j < 3; j ++){
            if(nTimes[j] == 0){
                candicate[j] = ID[i];                   //如果发现nTimes=0,则前面的重复完全抵消,重新选择一个candicate 
                nTimes[j] = 1;
            }else {
                if(candicate[j] == ID[i]) {
                    nTimes[j] ++;    //如果发现相同ID,重复次数加1 
                    break;
                }
            }
        }
        //与这三个ID都不同,则都要减1 
        if(j == 3){
           for(k = 0; k < 3; k++) nTimes[k]--;
        }  
    }
    return candicate;
}

抱歉!评论已关闭.