求职过程中,你会发现面试官的不少问题在《编程之美》中都能找到痕迹。想在企业招聘面试中成功忽悠,这本书不可不读。算了,不再打广告了,哈哈。
书中有一节探讨了“寻找发帖水王”,问题是从一堆ID构成的集合中,找到某个发帖总数超过帖子总数一半的ID。面试中的常见问题“从一堆整数中找到出现次数超过总数一半的整数”实际上就是该问题了。
在原题中,初步解法是对所有的ID进行排序,然后分析可知这个有序表中第N/2项便是问题的解,这个思路时间复杂度是O(N*log2N)。
改进的思路中不再对这些ID排序了,而是每次从ID列表中删除两个不同的ID,不断重复这个过程,直到遍历完所有的ID,此时要找的ID就出现啦,总的时间复杂度O(N)。该思路通过将原始问题逐步转化为规模较小的子问题,但是问题的解保持不变。
后面给出了一个扩展题:有三个ID的发帖数目都超过了帖子总数目的1/4,要求我们找出这三个ID。方法是类似的,即每次从ID列表中删除4个不同的ID,不断重复这个过程,最后即可得到这三个ID。
解决的思路:用数组candidate和count分别存储三个不同的疑似ID及其累计出现次数。遍历存储ID的数组,如果candidate数组中存在某个元素为空,则将当前遍历到的ID存进去;如果candidate中已经存储了三个不同的疑似ID,则将当前遍历到的ID与它们对比。对比的过程是,如果candidate中有某个ID与之相等,则将对应的count加1,否则将count中的所有元素都减1。
哎,认认真真写篇博客真费劲,好了,下面是贴代码的时候了,测试了部分数据,答案木有问题。如果有啥问题,欢迎提出交流哈。
#include<iostream>
using namespace std;
int candidate[3]={0},count[3]={0};
int findzero() // 遍历count数组,返回第一个为0的元素的index,如果没有0则返回-1
{
for(int i=0;i<3;i++)
if(count[i]==0)
return i;
return -1;
}
void find(int id[],int n)
{
for(int i=0;i<n;i++)
{
int fz=findzero();
if(fz>=0) // 表示count数组中有0元素,则存下当前的id
{
candidate[fz]=id[i];
count[fz]++;
}
else // 表示candidate数组中已经存在3个不同的元素
{
bool tag=false; // 表示当前的id和candidate中的3个id不等
for(int j=0;j<3;j++)
if(candidate[j]==id[i])
{
count[j]++;
tag=true;
continue;
}
if(tag==false)
{
for(int j=0;j<3;j++)
count[j]--;
}
}
}
}
int main()
{
int a[50],num;
cout<<"please input the number of IDS: ";
cin>>num;
cout<<"please input all the IDs: ";
for(int i=0;i<num;i++)
cin>>a[i];
find(a,num);
cout<<"They are "<<candidate[0]<<" "<<candidate[1]<<" "<<candidate[2]<<endl;
system("pause");
return 0;
}