第2章 数字之魅——数字中的技巧2.3

2.3寻找发帖“水王”

问题:求在一个ID列表中出现次数超过一半的ID。

对于该问题:一个比较直接的想法就是直接统计。统计每个ID出现的次数。然后寻找该数组中最大的数值。从而找出它的ID。

统计需要N,并且空间上要2*N(而且这里必须保证ID不能是小数而且ID是连续的)。然后对于寻找最大元素。一种是分治。log2 N。一种是建个最大堆。(复杂度)

当然还有一种就是打擂台。N。

总体上需要N+N。或者N+log2 N

另外一种想法是排序后找中间的元素。因为大过一半。所以必然是该ID。利用快排 N*log2 N 很省事。

而且这个可以推广到那个扩展问题。当元素是大过1/4的时候。那我们只要找下标在3/4的时候即可。

在编程之美上面,有一个十分巧妙的想法。就是删除2个不同的ID。用来减小问题的规模。(减小问题规模这种思想是我们应该要具备的,这算是一种消元法吧?)

同时这个想法也是比较容易操作的。而且空间和时间上都有很大的提升,空间是常数的。时间是N的级别。

当初我不解并且觉得神奇之处在于不同的ID如何实现?一个直观的想法就是用一个 int 型数来保存之前遇到的ID。可是继续思考下去这并不方便。

那就是维护当前的id。如果下一个遇到的不是这个id就抵消。如果是的话就统计这个id已经出现了2次。最后id保存的一定是出现最多次数的ID。

//这里假设 ID 是 int 型的,就不用定义Type了, 编程之美上用Type。当然书上更好。
int Find(int ID,int N)
{
    /*
    id 就是当前存储的id
    nTimes 代表这个id出现的次数
    */
    int id;
    int nTimes,i;
    nTimes = 0;
    for(i=0;i<N;i++)
    {
        if(nTimes==0)  
        {
            nTimes = 1;
            id = ID[i];
        }
        else
        {
            if(id == ID[i])
            {
                nTimes ++;
            }
            else
            {
                nTimes --;
            }
        }
    }
    return id;
}
编程之美——优美思想


反思:这一节的星数是一颗。但是我觉得这里面包含了缩小问题规模的重要思想。正如解决一个难题。我们可以把大化小。解小。而这种缩小问题规模的方法,在编程之美中是屡试不爽的。从求数组的最大值的那一篇章也可以了解到。从而引出了一个重要的算法思想。分治。

原文地址:https://www.cnblogs.com/Milkor/p/4351028.html