pat1078 错题备份

来源:互联网 发布:为什么不造高达 知乎 编辑:程序博客网 时间:2024/06/15 22:46

1078. Hashing (25)

时间限制
100 ms
内存限制
32000 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

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 (<=104) 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 410 6 4 15
Sample Output:
0 1 4 -

first code  15/25  , 两个测试点没有通过,仔细检查了一下 isPrime 方法,发现当 x = 0 和 x = 1 的时候,x 均不是素数,所以要进行判断:

#include <cstdio>#include <cstdlib>#include <string.h>bool mark [10001] ;int MSize , N ;int num[10001] ;bool isPrime( int x ){bool ok = true  ;int i ;for ( i = 2 ; i < x ; i++ ){if ( (x % i) == 0 ){ok = false ;break ;}}if ( i == x ){ok = true ;}return ok ;}int findMinPrime( int x ){int result ;x++ ;while (1){if ( isPrime( x ) ){result = x ;break ;}x++ ;}return result ;}void input (){memset( mark , false ,sizeof( mark )) ;scanf("%d%d", &MSize, &N ) ;if ( !isPrime( MSize) ){MSize = findMinPrime(MSize) ;}for ( int i = 0 ; i < N ; i++ ){scanf("%d", &num[i]) ;if ( mark[num[i]%MSize] == false ){mark[num[i]%MSize] = true ;num[i] = num[i]%MSize ;}else{num[i] = -1 ;}}}void output (){for ( int i = 0 ; i < N ; i++ ){if ( num[i] >= 0 )printf("%d", num[i]) ;elseprintf("-") ;if ( i != N-1 )printf(" ") ;}}int main ( void ){input() ;output() ;return 0 ;}

second code ,对方法 isPrime 进行修改之后,通过了一个测试点, 20/25,继续找原因:

#include <cstdio>#include <cstdlib>#include <string.h>bool mark [10009] ;int MSize , N ;int num[10009] ;bool isPrime( int x ){bool ok = true  ;int i ;if ( x == 1 || x == 0  )return false ;  for ( i = 2 ; i < x ; i++ ){if ( (x % i) == 0 ){ok = false ;break ;}}if ( i == x ){ok = true ;}return ok ;}int findMinPrime( int x ){int result ;x++ ;while (1){if ( isPrime( x ) ){result = x ;break ;}x++ ;}return result ;}void input (){memset( mark , false ,sizeof( mark )) ;scanf("%d%d", &MSize, &N ) ;if ( !isPrime( MSize) ){MSize = findMinPrime(MSize) ;}for ( int i = 0 ; i < N ; i++ )  // 1{scanf("%d", &num[i]) ;if ( mark[num[i]%MSize] == false ){mark[num[i]%MSize] = true ;num[i] = num[i]%MSize ;}else{num[i] = -1 ;}}}void output (){for ( int i = 0 ; i < N ; i++ ){if ( num[i] >= 0 )printf("%d", num[i]) ;elseprintf("-") ;if ( i != N-1 )printf(" ") ;}}int main ( void ){input() ;output() ;return 0 ;}


找了半天没有找到,原本以为将数组的下标修改为 10009就可以了,因为如果 MSize= N= 10000 的话, 对应的素数数值为 10007 ,但是这个并不会影响到

N 访问的范围 [0 .. 10000] 所以,对结果并没有什么影响。接下来有考虑到了,如果输入的数值 MSize 和 N的数值均为 0 的情况, 正常输出: 即什么都不显示

MSize = 一个常数数值, N= 0 ,正常输出,即什么都不显示。


虽然没有找到具体出错的原因,但是在查看提交的测试用例的时候,发现出错的地方,消耗的时间最长,并且查看代码之后,

发现消耗时间最大的方法是 input 方法 中的标记为  1 处的代码,所以判断出来出问题的地方一定是这个地方有特殊的数据情况没有考虑到。


这段代码的核心思想就是:设置一个标记数组 mark ,mark 中的所有元素值均置为 false 

 但凡是通过散列定位到 位序为 x 的数值 key , 即  x = key%TSize ,


首先判断,mark[x] 是否为  false , 如果为 false 的话, 则说明重定位位序 x 并没有与前面的 key 得到的位序 发生冲突,

故将 num[i] <- x , 并将 mark[x] <- true , 这样的话, 就把求得的有效重定位位序 存放在num 数组中, 

并将 标记数组关于为序 x 进行标记,这样在后续的key 求取重定位位序的时候,如果与刚刚求得的 x 数值相等的话,

 则会将其位序置为无效,在这里如果为序无效的话, 则将 num[i] <- -1 ,


 这样的话, 判断num [0 .. N -1] 中的数值是否是 >= 0 的,

如果是, 则将num 中的数据进行输出,如果不是,则输出无效定位标志 '-'


通过创建一个标记数组,以空间置换时间的方式来降低时间复杂度典型使用方法,因为这样做就不会每一次都对num 中的数据进行重新扫描比对。

仅仅查找标记数组即可,将时间复杂度从 O(N) , 降低到了 O(1) . 其中N 为 num 的数组长度。


这篇博客当做错题备份吧~ 不甘心....

0 0
原创粉丝点击