寻找发帖水王
2013-06-09 21:18 夜与周公 阅读(297) 评论(0) 编辑 收藏 举报在<<编程之美>>这本书中提到了发帖水王的问题。
原始问题:Tango是微软亚洲研究院的一个试验项目。研究院的员工和实习生们都很喜欢在Tango上面交流灌水。传说,Tango有一大“水王”,他不但喜欢发贴,还会回复其他ID发的每个帖子。坊间风闻该“水王”发帖数目超过了帖子总数的一半。如果你有一个当前论坛上所有帖子(包括回帖)的列表,其中帖子作者的ID也在表中,你能快速找出这个传说中的Tango水王吗?
扩展版本:随着Tango的发展,管理员发现,“超级水王”没有了。统计结果表明,有3个发帖很多的ID,他们的发帖数目都超过了帖子总数目N的1/4。你能从发帖ID列表中快速找出他们的ID吗?
先看原始问题,假设ID序列是已经排序好的,序列的长度为N,那么第2/N个元素一定是我们需要找的那个元素,算法时间复杂度O(1)。然而,若是未排序的,那么算法排序的时间复杂度O(N*logN)。很显然,对于这个问题,如果只用用排序方法解决,那就没有多大的存在价值,因此,需要进一步的思考当前问题。实际上,如果我们在序列中删除两个不同的元素,我们需要寻找的“水王”,仍然存在于余下的序列当中,但问题的规模已经被我们简化(适合算法设计思想中的分治与递归)。
#include <iostream> using namespace std; typedef int Find_Type; Find_Type find_type(int* array, int N) { Find_Type candinate; int nTimes=0; for (int i=0; i != N; i++) { if ( 0 == nTimes) { candinate = array[i]; nTimes++; } else { if (array[i] == candinate) { nTimes++; } else { nTimes--; } } } return candinate; } int main() { int array[] = {1,2,2,2,3,4,2,2,5}; Find_Type candinate = find_type(array, sizeof(array)/ sizeof(int)); cout<<candinate; system("pause"); return 0; }
拓展版本类似与原问题,将三个ID看出一个整体,解决思路与第一个相似,不同的是的需要保存三个nTimes。在遍历过程中,当前ID不同与保存的三个ID,若某个ID的nTimes等于0,则用当前ID替换掉该ID,若不存在,则将三个ID的nTimes均减1。
#include <iostream> using namespace std; typedef int Find_Type; Find_Type* find_3type(int* array, int N) { const int cand_num = 3; Find_Type *cand_list = new Find_Type[cand_num]; int nTimes[cand_num] = {0}; for (int i = 0; i != cand_num; i++) { cand_list[i] = -1; } for (int i = 0; i != N; i++) { int currentID = array[i]; int tag = -1; for (int i = 0; i != cand_num; i++) //判断当前的ID与保存的三个ID某个ID相同, -1表示不存在 { if (currentID == cand_list[i]) { tag = i; break; } } if (-1 == tag) //当前ID与保存的三个ID均不同 { int j=0; for (; j != cand_num; j++) { if (0 == nTimes[j]) //如果三个ID中,某个ID的nTime等于0,则将当前ID赋值给该ID,其nTime赋值1 { cand_list[j] = currentID; nTimes[j] = 1; break; } } if (j == cand_num) //如果三个ID均不存在nTime等于0的,则将三个ID的nTime减1 { for (int k = 0; k != cand_num; k++) { nTimes[k]--; } } } else //当前ID与保存的某个ID相同,则该ID的nTimes加1 { nTimes[tag]++; } } return cand_list; } int main() { int array[] = {1,2,2,3,4,2,2,3,3,4,4}; int cand_num =3; Find_Type* cand_list = find_3type(array,sizeof(array) / sizeof(int)); for (int i = 0; i != cand_num; i++) cout<<cand_list[i]<<"\t"; system("pause"); return 0; }