今天遇到了一道难题.题目如下:
SumTime limit:
30 Seconds
Memory limit:
32768K Bytes
Submitted:
Accepted:
Sum
Mr. Jojer is given n numbers and an extra integer x, he wants to know whether there are two numbers whose sum is x.
Input
The input file contains several test cases. The first line of each test case contains two integers, n(<=1000001) and x. From the next line of each test case, there are n numbers.
Output
Each test case corresponds to a line in the output, which is either "YES" if there exists an answer or "NO" if not.
Sample Input
3 3
1 2 3
2 3
1 3
Sample Output
YES
NO
从题目的限制条件可以看出,要求要在1000001多个整数中查找两个其和为X的整数,其计算量是十分巨大的.而题目要求的是30秒中完成一批数目的测试(几组).如果采用一般的循环2阶相加比较,是现在完不成的.我这里有两套解决办法.
1.以内存换速度.
在为了提高运行速度的问题上,首先就应该想到的是以空间代价换取时间上的代价.最能体现这点的就是我们数据结构中所学习的Hash表.Hash表查找速度十分快,可能我们这里如何把Hash表应用进来呢?我采用了比较笨的办法.
循环每组数中的每个元素,首先检查其值是否存在Hash表中,如果存在,说明"YES"。否则将其 X - 元素 的值插入一个Hash表。那么这样下去,我只需要一个1阶的算法就能完成。不过这个Hash表十分巨大。不过,我们只需要把在一般范围内的整数放进Hash表记录,如果数值的范围超过了Hash能表示的范围,就单独出来存放在一个线性表中。
下面是我已经调试通过,并且在ACM Online Judge上Accpeted的源程序。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_N 3000002
long integers[MAX_N];
char regularTab[MAX_N];
long extendTab[MAX_N];
long numExt;
long n;
long x;
void insertTab(int a);
int lookup(int a);
int main()
{
long i,j;
long m;
int Yes;
while(scanf("%ld%ld",&n,&x) == 2)
{
memset(regularTab,0,MAX_N);
memset(extendTab,0,MAX_N*sizeof(long));
numExt = 0;
Yes = 0;
for(i=0; i<n; i++)
{
scanf("%ld",&integers[i]);
}
for(i=0;i<n;i++)
{
if(lookup(integers[i]))
{
printf("YES\n");
i = n;
Yes = 1;
break;
}
else
{
insertTab(x-integers[i]);
}
}
if(Yes == 0)
printf("NO\n");
}
return 1;
}
void insertTab(int a)
{
if(a > -MAX_N/2 && a < MAX_N/2)
{
regularTab[a+MAX_N/2] = 1;
}
else
{
extendTab[numExt++] = a;
}
}
int lookup(int a)
{
if(a > -MAX_N/2 && a < MAX_N/2)
{
return regularTab[a+MAX_N/2];
}
else
{
long i;
for(i=0;i<numExt; i++)
{
if(extendTab[i] == a)
return 1;
}
return 0;
}
}
2.使用QuickSort和qsort函数
快速排序的算法不用在这里多讲了。在C语言的stdlib.h中已经提供了一个汇编级别的qsort函数。这道题目使用快速排序的办法就是让所有的数列先排序,然后再进行查找。虽然排序也是二阶算法,但是由于QuickSort的特殊性,使得排序的过程还是比较快,一旦排序完成后,根据X进行二分查找,几步就可以完成了。具体的实现程序我这里没有。不过我觉得qsort的函数使用是十分重要的,所以我从msdn上抄袭了qsort函数的示例代码。
void qsort(
void *base,
size_t num,
size_t width,
int (__cdecl *compare )(const void *, const void *)
);
Example// crt_qsort.c
// arguments: every good boy deserves favor
/* This program reads the command-line
* parameters and uses qsort to sort them. It
* then displays the sorted arguments.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int compare( const void *arg1, const void *arg2 );
int main( int argc, char **argv )
{
int i;
/* Eliminate argv[0] from sort: */
argv++;
argc--;
/* Sort remaining args using Quicksort algorithm: */
qsort( (void *)argv, (size_t)argc, sizeof( char * ), compare );
/* Output sorted list: */
for( i = 0; i < argc; ++i )
printf( " %s", argv[i] );
printf( "\n" );
}
int compare( const void *arg1, const void *arg2 )
{
/* Compare all of both strings: */
return _stricmp( * ( char** ) arg1, * ( char** ) arg2 );
}
Output boy deserves every favor good