问题:求在一个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;
}
编程之美——优美思想

相关文章:

  • 2021-11-18
  • 2022-03-04
  • 2021-04-19
  • 2022-02-10
  • 2021-08-14
  • 2021-12-23
  • 2021-10-13
  • 2021-11-13
猜你喜欢
  • 2021-11-25
  • 2021-10-20
  • 2022-03-02
  • 2021-09-23
  • 2021-06-02
  • 2021-05-17
  • 2021-11-25
相关资源
相似解决方案