编程之美_2.3_寻找发帖水王
2012-05-22 14:30
260 查看
前提:给出一个ID数组,其中每个ID都可能重复出现,其中一个ID的重复出现个数超过了数组长度的一半。
问题:要找出这个水王ID
要求:要求时间和空间代价最小
等价于:找出数组中元素过半的元素,要求时间和空间代价最小
扩展:
1、ID数组中,有三个水王ID,这三个水王ID重复出现的次数,都超过了数组长度的1/4。要求快速找到这3个水王ID。
2、ID数组中,有 K个水王ID,这K个水王ID重复出现的次数,都超过了列表长度的1/(k+1)。要求快速找到这K个水王ID。
~~~~~~~~~~~~~分割线~~~~~~~~~~~~~~~~
前提:给出一个ID数组,其中每个ID都可能重复出现,其中一个ID的重复出现个数超过了数组长度的一半。
问题:要找出这个水王ID
要求:要求时间和空间代价最小
方法一:先对ID数组进行排序,再遍历排序后的序列,统计每个ID的次数,从而寻找到最大次数的ID。
时间复杂度 O(nlgn)
+ O(n) = O(nlgn)
不需要另外开辟空间
方法二:先对ID数组进行排序,水王的ID必然是数组中间那个
时间复杂度O(nlgn)+ O(1)= O(nlgn)
不需要另外开辟空间
方法三:不进行排序,而且把时间复杂度降到 O(n),即仅仅遍历一遍数组就找到
思路:每次删除两个不同的ID,最终得到那个ID就是我们要找的水帖ID
时间复杂度O(n)
+ 空间复杂度O(1)。
分析:由于水王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抵消了
代码:
扩展:
1、ID数组中,有三个水王ID,这三个水王ID重复出现的次数,都超过了数组长度的1/4。要求快速找到这3个水王ID。
2、ID数组中,有 K个水王ID,这K个水王ID重复出现的次数,都超过了列表长度的1/(k+1)。要求快速找到这K个水王ID。
扩展1与扩展2的思路是一样的,只不过开辟的数组大小不同而已
思路:每一个水ID数总是大于所有非水ID的总数,思路是类似的,每次删除四个不同的ID,不影响"
那三个水ID在剩余ID中出现仍然查过1/4"这个事实。因此,我们可以每次删除四个不同的ID,直到剩余3个水ID为止
代码:
怎么体现“删除四个不同ID”这一动作
在处理一个ID时,都要与CandidateID[i]相比较,如果与CandidateID[i]中的数全都不一样是,就相当于找到了四个不同数,让三个count[i]都--,此时就可以表示,一次删除四个不同ID了。
问题:要找出这个水王ID
要求:要求时间和空间代价最小
等价于:找出数组中元素过半的元素,要求时间和空间代价最小
扩展:
1、ID数组中,有三个水王ID,这三个水王ID重复出现的次数,都超过了数组长度的1/4。要求快速找到这3个水王ID。
2、ID数组中,有 K个水王ID,这K个水王ID重复出现的次数,都超过了列表长度的1/(k+1)。要求快速找到这K个水王ID。
~~~~~~~~~~~~~分割线~~~~~~~~~~~~~~~~
前提:给出一个ID数组,其中每个ID都可能重复出现,其中一个ID的重复出现个数超过了数组长度的一半。
问题:要找出这个水王ID
要求:要求时间和空间代价最小
方法一:先对ID数组进行排序,再遍历排序后的序列,统计每个ID的次数,从而寻找到最大次数的ID。
时间复杂度 O(nlgn)
+ O(n) = O(nlgn)
不需要另外开辟空间
方法二:先对ID数组进行排序,水王的ID必然是数组中间那个
时间复杂度O(nlgn)+ O(1)= O(nlgn)
不需要另外开辟空间
方法三:不进行排序,而且把时间复杂度降到 O(n),即仅仅遍历一遍数组就找到
思路:每次删除两个不同的ID,最终得到那个ID就是我们要找的水帖ID
时间复杂度O(n)
+ 空间复杂度O(1)。
分析:由于水王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个水王ID,这K个水王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了。
相关文章推荐
- [编程之美] PSet2.3 寻找发帖“水王”
- 编程之美-2.3-寻找发帖“水王”
- 编程之美 2.3 寻找发帖水王扩展问题
- 编程之美 2.3寻找发帖‘水王’ 扩展问题
- 编程之美 2.3 寻找发帖“水王”
- 编程之美-2.3、寻找发帖水王id占一半
- 编程之美-2.3-寻找发帖“水王”
- 编程之美 2.3 寻找发帖“水王”
- 编程之美--2.3 寻找发帖的水王
- 读书笔记之编程之美 - 2.3 寻找发帖“水王”
- 编程之美-2.3-寻找发帖“水王”
- 编程之美 代码 P125 2.3寻找发帖水王
- 【编程之美】2.3寻找发帖水王(数组中出现次数超过一半的数字)
- 编程之美--寻找发帖“水王”的扩张问题--代码实现
- 2.3 寻找发帖水王
- 编程之美2.3寻找发帖水王和扩展问题
- 编程之美 2.12 快速寻找满足条件的两个数 解法三证明 (算法导论 第二版 2.3-7 在n个元素的集合S中找到两个和为x的元素)
- 2.3--寻找发帖水王
- 编程之美: 第二章 数字之魅 2.3_1寻找发帖超过总帖1/4的水王