重新开始战斗10-编程之美-寻找发帖水王

本文介绍了一种高效查找数组中出现次数超过一半元素的算法。通过巧妙地遍历和计数,避免了排序带来的高时间复杂度,实现了线性时间复杂度的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

n问题描述:

给定一个论坛所有帖子的列表,其中帖子作者的id也在列表中,水王的发帖数目超过了所有帖子的半,请设计算法,找出水王!

 

问题分析:

该问题很直接,简化一下,就是找一个数组中,出现次数最多的数,其中,这个出现次数最多的数的出现次数占整个数组大小>50%。

最直观的方法是对数组进行排序,然后遍历,即可找出出现次数最多的数。总的时间复杂度为NlogN+N。

那么能不能不进行排序而用一个比较的方法找到这个出现次数最多的数?

注意一个性质——出现的次数大于整个数大小的组一半。仔细想想这个性质,如果每次删除两个不同的id,一样可以保证这个原来出现次数最多的数在删除两个不同的数后,依然满足关系,依次类推,不断缩小数组的大小,最后就可以找到这个出现次数最多的数。

这种思想很巧妙,但是不难想象。更精髓的地方在于如何将这个思想用代码实现。

 

设想一下,从数组的第一个数开始,如果第二个数是不同的,那么我们之前把指针移到第三个数,表示前面两个数已经被删除了;但是如果第二个数和第一个数相同,那么该怎么办?书中的伪码是这样做的,找第三个和第四个数,如果第三和第四都不同于第一个(第二个数,第一个数等于第二个数),则都删除,相当于删除了两队。

程序的巧妙之处在于用一个变量记录一个数的出现次数,第一次出现num=1,如果下一个数是一样的,则num++,否则则num--,当num = 0,说明了如果这个数出现了n,那么当n=0时,一定有n个数与之相同,这全部删除,相当于删除了n对!

 

伪代码:

Type Find(Type *ID,int N)

{

         Typecandidate;

         Intnum,I;

For(I = num = 0;I < N; i++)

{

         If(num == 0)

{

                   Candidate = ID[i];

                   Num++;

}

         Else

         {

                   If(candidate == ID[i])

                            Num++;

                   Else

                            Num--;

}

}

Returncandidate;

}

书中的代码

If(num == 0)

{

         Candidate = ID[i];

}

我改为:

If(num == 0)

{

         Candidate = ID[i];

         Num++;

}

不然永远不能进入1级else

 

我用自己的程序验证了这一点,结果如下:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值