PAT 1078 Hashing [平方探查法] [素数判断]

本文介绍PAT 1078题目的解题思路,涉及平方探查法解决哈希冲突以及素数判断的方法。题目要求在哈希表中插入一系列互不相同的正整数,哈希函数为H(key)=key%TSize,并使用平方探查法解决冲突。若用户提供的最大表尺寸非素数,需选择大于该尺寸的最小素数作为表尺寸。文章讨论了素数判断的常见方法,包括O(sqrt(n))的时间复杂度和素数筛法。并提醒注意冲突处理时的位置判断,以及数组大小的设定,避免超时或答案错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

The task of this problem is simple: insert a sequence of distinct positive integers into a hash table, and output the positions of the input numbers. The hash function is defined to be H(key)=key%TSize where TSize is the maximum size of the hash table. Quadratic probing (with positive increments only) is used to solve the collisions.

Note that the table size is better to be prime. If the maximum size given by the user is not prime, you must re-define the table size to be the smallest prime number which is larger than the size given by the user.

Input Specification:

Each input file contains one test case. For each case, the first line contains two positive numbers: MSize (≤10​4​​) and N (≤MSize) which are the user-defined table size and the number of input numbers, respectively. Then N distinct positive integers are given in the next line. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print the corresponding positions (index starts from 0) of the input numbers in one line. All the numbers in a line are separated by a space, and there must be no extra space at the end of the line. In case it is impossible to insert the number, print "-" instead.

Sample Input:

4 4
10 6 4 15

Sample Output:

0 1 4 -

-------------------------------这是题目和解题的分割线-------------------------------

先来回顾一下素数判断吧~

①最常见的方法,复杂度O(sqrt(n))

bool isPrime(int n)
{
	if(n<=1) return false; //1既不是素数也不是合数 
	//如果是合数,因子一个在sqr的左边,一个在右边,判断其中一边即可
	int sqr = (int)sqrt(n*1.0); //sqrt的参数要求是浮点数 *1.0
	for(int i=2;i<=sqr;i++)
		if(n%i==0) return false;
	return true;
}

枚举部分的复杂度是O(n),所以这个方法在判断素数的总函数里复杂度是O(n*sqrt(n))。

当n不超过10^5时,是不会超时的。

 

②如果遇到n很大的情况,可以用素数筛法,O(nloglogn)。

举个例子,求1-10的所有素数。

1. 2是素数(唯一需要事先确定),因此筛去所有2的倍数,即4、6、8、10

2. 3没有被前面的步骤筛去,因此3是素数,筛去所有3的倍数,即6、9

3. 4已经在1中被筛去,因此4不是素数

4. 5没有被前面的步骤筛去,因此5是素数,筛去所有5的倍数,即10

..............以此类推

由此可见,当从小到大到达某数x时,如果x没有被前面步骤的数字筛去,那么a一定是素数。

void findPrime()
{
	for(int i=2;i<maxN;i++) //maxN是表长
	{
		//初始化a[i]为false,如果i为素数,a[i] = true 
		if(a[i]==false)
		{
			//把素数i存在数组里 
			prime[count++] = i;
			//在剩余的数字里遍历,筛去该素数的倍数,置为true 
			for(int j=i+1;j<maxN;j+=i)
				a[j] = true;
		}
	} 
} 

好啦回到题目本身!

有几个点需要注意一下,

①哈希表的冲突处理 Quadratic probing ,中文名是平方探查法,即当H(a)发生冲突时,令a等于a+1^2、a-1^2、a+2^2、

a-2^2...的顺序调整a的值,直到不冲突或者到达边界为止。题目说明(with positive increments only),只要往正向解决冲突,

即a+1^2、a+2^2...

②测试点1答案错误,可能是错把1当质数了。

②测试点3运行超时,是因为在冲突处理的过程中,找到位置时没有及时中断这个循环。

③测试点2、3都答案错误,是数组开的太小了,我最早开的10005就不够,至少10007才行。

#include<cstdio>
#include<math.h>

int isPrime(int x)
{
	if(x<=1) return 0; //1不是素数 
	int sqr = (int)sqrt(x*1.0);
	for(int i=2;i<=sqr;i++)
		if(x%i==0) return 0;
	return 1;
}

int main()
{
	//数组至少10007以上 
	int i,n,m,a[10010],hash[10010] = {};
	scanf("%d%d",&m,&n);
	for(i=0;i<n;i++)
		scanf("%d",&a[i]);
	while(!isPrime(m)) m++;
	for(i=0;i<n;i++)
	{
		int flag = 0;	
		if(!hash[a[i]%m])
		{
			hash[a[i]%m] = 1;
			a[i] = a[i]%m;
		}			
		else
		{
			//平方探查法 
			for(int j=1;j<=m;j++)
			{
				if(!hash[(a[i]+j*j)%m])
				{
					hash[(a[i]+j*j)%m] = 1;
					a[i] = (a[i]+j*j)%m;
					flag = 1;
					break; //及时中断 
				}			
			}
			if(!flag) a[i] = -1;
		}	
	}
	for(i=0;i<n;i++)
	{
		if(a[i]!=-1) printf("%d",a[i]);
		else printf("-");
		if(i!=n-1) printf(" ");
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值