现在的位置: 首页 > 综合 > 正文

[各种面试题]来自陈利人先生微博面试题—出现超过N/3次的查询

2018年04月12日 ⁄ 综合 ⁄ 共 1651字 ⁄ 字号 评论关闭

题目是有一堆查询,可能有一些查询出现次数超过 N/3,希望能找出这些查询词。

 

思路是:

利用三色旗问题的思想把针对某个查询将数组分为3部分,小于,等于,大于,同时也得到前两个区间的右下标分别为small,equal:

1.如果equal-small>=n/3,很明显选中的这个查询出现了超过n/3次,否则该词出现次数肯定低于n/3。

2.然后我们再检查左右两边的大小是否还不小于n/3,如果是,则在该区间递归。

3.下面代码中简单的选取区间第一个值作为比较值,而实际上应当引入三位取中、五位取中或者random来选取这个比较值,大家可以自行修改。

另外为了简化问题,查询串也用整数来代替了。

 

 

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;

int query[200];
int n;
int answer[3];
int nAns;

bool input()
{
	cin>>n;
	for(int i=0;i<n;i++)
		cin>>query[i];
	nAns=0;
	return n!=0;
}

void process(int start,int end)
{
	int piv=query[start];
	int small=start,equal=start,big=end;
	while(equal<=big)
	{
		if (query[equal]==piv )
			equal++;
		else if (query[equal]<piv )
			swap(query[small++],query[equal++]);
		else
		{
			while(big>equal&&query[big]>piv)
				big--;
			swap(query[big],query[equal]);
			big--;
		}
	}
	if (equal-small>= n/3)
		answer[nAns++]=piv;
	if ( small -start >=n/3)
		process(start,small-1);
	if ( end-equal+1 >=n/3 )
		process(equal,end);
}

int main()
{
	while(input())
	{
		process(0,n-1);
		for(int i=0;i<nAns;i++)
			cout<< answer[i] <<endl;
	}
}

之前就在想这个算法虽然能解,但是一直觉得效率应该不是O(N)的,因为一次PATITION之后还要在两边进行递归,也就是说并未像FINDKTH那样能减小一半的搜索空间,所以这个算法的效率应该不是O(N)。

 

因此后来借鉴用一个变量来解决“出现超过一半的数字”的方法,写了下面一个类似的算法,这次是用两个变量(因为最多只有两个能超过N/3)。

记得最后留下的不一定是答案,还需要CHECK一下。

这个算法无疑是O(n)的。

bool check(int k)
{
	int cnt=0;
	for(int i=0;i<n;i++)
		if ( query[i]==k)
			cnt++;
	return cnt>=n/3;
}
void process2()
{
	int num1=-1,time1=0;
	int num2=-1,time2=0;

	for (int i=0;i<n;i++)
	{
		if(num1==-1)
		{
			num1=query[i];
			time1=1;
		}
		else if (query[i]==num1 )
			time1++;
		else if (num2==-1)
		{
			num2=query[i];
			time2=1;
		}
		else if ( query[i]==num2)
			time2++;
		else
		{
			if ( --time1 == 0)
				num1=-1;
			if ( --time2==0 )
				num2=-1;
			if ( time1==0 && time2>0 )
			{
				num1=num2;
				time1=time2;
				num2=-1;
				time2=0;
			}
		}
	}
	if ( num1!=-1 &&check(num1) )
		answer[nAns++]=num1;
	if (num2!=-1&&check(num2))
		answer[nAns++]=num2;
}

 

 

抱歉!评论已关闭.