编程之美_2.3_寻找发帖水王

前提:给出一个ID数组,其中每个ID都可能重复出现,其中一个ID的重复出现个数超过了数组长度的一半。

问题:要找出这个水王ID

要求:要求时间和空间代价最小

等价于找出数组中元素过半的元素,要求时间和空间代价最小

扩展:

1、ID数组中,有三个水王ID,这三个水王ID重复出现的次数,都超过了数组长度的1/4。要求快速找到这3水王ID

2、ID数组中,有 K水王IDK水王ID重复出现的次数,都超过了列表长度的1/k+1)。要求快速找到这K水王ID


~~~~~~~~~~~~~分割线~~~~~~~~~~~~~~~~


前提:给出一个ID数组,其中每个ID都可能重复出现,其中一个ID的重复出现个数超过了数组长度的一半。

问题:要找出这个水王ID

要求:要求时间和空间代价最小

方法一:先对ID数组进行排序,再遍历排序后的序列,统计每个ID的次数,从而寻找到最大次数的ID

时间复杂度  Onlgn + On = Onlgn

不需要另外开辟空间


方法二:先对ID数组进行排序,水王的ID必然是数组中间那个

时间复杂度O(nlgn)+ O(1)= Onlgn

不需要另外开辟空间


方法三:不进行排序,而且把时间复杂度降到 On),即仅仅遍历一遍数组就找到

思路:每次删除两个不同的ID,最终得到那个ID就是我们要找的水帖ID

时间复杂度On + 空间复杂度O1)。

分析:由于水王ID的个数占ID数组长度一半以上, 即水王ID的总数会大于所有非水ID总数之和,因此,每次删除两个不同的id,无论删减顺序如何,最后超过一半以上的ID一定是不会被删减完的,也是唯一一个不会被删减掉的ID。通过这点,将不断重复这个过程,将ID数逐渐降低,最后就可以得出这个水ID。

一种最极端的状况就是,所有非水王ID都与水王ID抵消。但因为,水王发的帖占大于总帖数一半,故其水王发的贴 总数 减去 其他人发的所有帖子之和,总会大于0,所以最终返回的ID总会是水王的ID

难点:

如何每次删除两个不同的ID:

可以使用CandidateID保存上一次遇到的ID,count为此ID在抵消后剩余的个数

如果遇到相同的ID,count++,表示有该CandidateID又出现一个,也即是有可以与不同的ID抵消一次

如果遇到不同的ID,count–,此时不做其他操作

也就表示,现在ID 和 CandidateID已经被抵消了,下次再处理时,要首先检查count值,如果count=0,表示刚刚候选CandidateID

已经抵消完,要重新为其赋值,此时的ID不是上次与CandidateID抵消的ID了,而是本次刚刚要处理的ID,此时就表示已经上一次ID

和candidateID抵消了

代码:

使用两个变量
CandidateID:保存候选水帖ID,初始化为第一个贴ID
count:保存该ID的和不同的ID抵消过后,剩余的次数

然后遍历ID列表,得到下一个待处理的ID,
	如果当前CandidateID没有保存过ID 或 已经删减完(即ID对应次数为0),
		那么保存待处理的ID,并且计数设置为1;
	如果遇到的ID刚好是保存的CandidateID,
		那么计数加1;
	如果遇到的ID是一个新的ID,//候选ID 和 现在遇到的ID一起丢掉
		那么ID的计数减1。
这样遍历之后,整个遍历下来,相同的ID都会被累加起来,而不同ID之间会互相抵消,最后剩下来的candidateID就是所求水王ID。

扩展:

1、ID数组中,有三个水王ID,这三个水王ID重复出现的次数,都超过了数组长度的1/4。要求快速找到这3水王ID

2、ID数组中,有 K水王IDK水王ID重复出现的次数,都超过了列表长度的1/k+1)。要求快速找到这K水王ID

扩展1与扩展2的思路是一样的,只不过开辟的数组大小不同而已

思路:每一个水ID总是大于所有非水ID的总数,思路是类似的,每次删除四个不同的ID,不影响” 那三个水ID在剩余ID中出现仍然查过1/4″这个事实。因此,我们可以每次删除四个不同的ID,直到剩余3个水ID为止

代码:

使用两个数组处理
用candidateID[3]记录三个候选ID
用count[3]记录它们的累积次数

然后遍历整个ID列表,每处理一个ID
	若与candidateID[i]中的某一个相同,
		则对应的count[i]++,
	若与三个都不同,
		将三个count[i]--
这样遍历之后,整个遍历下来,相同的ID都会被累加起来,而不同ID之间会互相抵消,最后剩下来的candidateID[i]就是所求

难点:

怎么体现“删除四个不同ID”这一动作

在处理一个ID时,都要与CandidateID[i]相比较,如果与CandidateID[i]中的数全都不一样是,就相当于找到了四个不同数,让三个count[i]都–,此时就可以表示,一次删除四个不同ID了。


    原文作者:insistgogo
    原文地址: https://blog.csdn.net/insistGoGo/article/details/7590844
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞