《编程之美》寻找发帖水王扩展问题的代码实现

    求职过程中,你会发现面试官的不少问题在《编程之美》中都能找到痕迹。想在企业招聘面试中成功忽悠,这本书不可不读。算了,不再打广告了,哈哈。

    书中有一节探讨了“寻找发帖水王”,问题是从一堆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;
}

 

点赞