笔试题一
前些天在班级群里看到一个笔试题:
从1到100000中任意拿掉两个数字,把剩下的99998个数顺序打乱,并且放入数组A中。要求只扫描一遍,把这两个数找出来;可以使用最多不超过5个局部变量,不能使用数组变量,并且不能改变原数组的值。
也想不到什么更好的解法,原解法是顺序扫一边求得所有数的乘积(mul_res)、和(sum_res)。用(N!)/mul_res得到两个数的乘积,1到100000的和减去sum_res得到两个数之和。 解这个方程得到两个数。关键是N!太大了,C会溢出。刚开始想想乘积每次模100000,后来写了一下还是不对的,因为模100000中可能就出现了0,后面全为0了。最后想到这么一个办法,不过中间 除法和比较多。也许有更快的解法。
file:///home/heipang/document/wiki/Home_Page/Computer/笔试题.html
//1到100 000 #include <iostream> #include <math.h> using namespace std; #define N 100000 typedef long long LL; LL a; LL b; LL vec[N]; int cnt; LL MAX_MUL; void Find(const LL* vec) { int sum=0; LL mul=1; LL Now=1; for(int i=0;i<cnt;i++) { sum+=vec[i]; while(mul%vec[i]!=0) mul*=(++Now); mul/=vec[i]; } while(Now<100000) mul*=(++Now); LL diff=((1+N)*N)/2-sum; cout<<diff<<" "<<mul<<endl; LL a=(diff+sqrt(diff*diff-4*mul))/2; cout<<a<<" "<<diff-a<<endl; } int main() { srand(time(NULL)); a=(rand()%100000)+1; b=(rand()%100000)+1; cnt=0; for(int i=1;i<=N;i++) { if(i!=a&&i!=b) vec[cnt++]=i; } cout<<a<<" "<<b<<" "<<endl; cout<<a+b<<" "<<a*b<<endl; Find(vec); }
———————————————————-
经熊师兄指点,上面的解法还是不对,如果vec前面刚好为比较大的素数,mul就溢出了。正确的解法应该为求x+y=B, x^2+y^2=A, 1-100000的平方和可以用double存下来,然后减去vec里面的平方和就得到x^2+y^2的值。
void Find(const LL* vec) { double sum=0; double square_sum=0; for(int i=0;i<cnt;i++) { sum+=vec[i]; square_sum+=(vec[i]*vec[i]); } double diff=((1+N)*N)/2-sum; double square_sum_diff= ((double)N*(N+1)*(2*(double)N+1))/6 - square_sum; cout<<diff<<" "<<square_sum_diff<<endl; a=(2*(diff)+sqrt(8*square_sum_diff-4*diff*diff))/4; cout<<a<<" "<<diff-a<<endl; }






十月 5th, 2010 at 11:31 上午
1、一直在学VC++,算法基本上没研究过……我悲剧了!看来,从下学期开始就要开始为笔试、面试准备了,要恶补基础了!!!对了,大三下学期开始准备,到大四上学期的十月份,这个时间会不会太短了?
[回复]
moorekang 回复:
十月 5th, 2010 at 11:35 上午
越早越好 呵呵
数据结构和算法是基础
[回复]
十月 6th, 2010 at 7:36 下午
我想到的是 想求出 x0+x1 = sum, 接着对 数组进行异或操作(同1-10000的异或)
也就是 x0^x1…^x1000^1^2….^10000得到 x0^x1=value(x^x=0,x^0=x) 接下来就是求这两个方程了。(sum-x1)^x1 = value 接下来是二进制操作了,根据sum和value小心的探测x1的每一位了(这个没想好)。
[回复]
moorekang 回复:
十月 6th, 2010 at 7:41 下午
x0+x1=sum
x0^x1=value
这个解是唯一的吗?
[回复]