一道算法面试题,大家讨论看看

一道算法面试题,大家讨论看看
题目:

从1到N(100000)中任意拿掉两个数,把剩下的99998个数顺序打乱,并且放入数组A中。要求只扫描一遍数组,把这两个数找出来。可以使用最到不超过5个局部变量,不能用数组变量,并且不能改变原数组的值。

思路:

遍历一次数组,求出这两个数的和a+b 与积a*b
a+b = 1+2+3+4+...+N- sum(A[]);    (1)
a*b =  1*2*3*4*...*N / multi(A[]);   (2)

主要解决sum与multi的溢出问题

(1) 可化为 (N-A[0]) + (N-1-A[1]) + ...+ (3-A[N-3]) + 2 + 1

(2) 可以用对数来代替原数进行求积的等价运算,避免溢出的问题,但是这种方法会产生一些精度上的问题,不知道大家有什么更好的方法!
先求出log(a*b) :
                         = log(1*2*3*4*....*N)/log(A[0]*A[1]*A[2]*...*A[N-3])
                         = log(N)-log(A[0]) + log(N-1)-log(A[1]) + ... +log(3)-log(A[N-3]) + log(2) + log(1)
         
知道了两数的和与积,由此就可以计算出a跟b的值来.

代码如下:


#include 
< iostream >
#include 
< Ctime >
#include 
< Cmath >
using   namespace  std;


#define  N 100000

// 生成不同的随机数的数组
void  GetDiffRandomNum( int  A[],  int  n)
{
    srand(unsigned(time(NULL)));
    
int i=0;

    
for(int index = n-1; index > 0; index--)
    
{
        i 
= rand() % index;
        swap(A[i], A[index]);
    }


}



int  main()
{
  
    
int A[N]={0};
    
for(int i=0; i<N; i++)
    
{
        A[i] 
= i+1;
    }

    GetDiffRandomNum(A, N);
    
//DISPLAY(A, N);
    
    unsigned 
int sum = 0;
    
double logSum = 0;

    
for(i=0; i<N-2; i++)
    
{
        sum 
+= N-i-A[i];             
        logSum 
+= log(N-i)-log(A[i]);
    }

    sum 
+= 2 + 1;
    logSum 
+= log(2)+log(1);

    
double multi = exp(logSum);

    
//两数的和与积
    cout<<int(sum)<<'\t'<<int(multi)<<endl;

    
//求出两数
    for(i=1; i<=N; i++)
    
{
        
double temp = i*(sum-i);
        
if(multi-0.5<=temp && temp <= multi+0.5)
            cout
<<i<<'\t'<<int(sum-i)<<endl;
    }

 
    
return 0;
}



PS(谢谢枝~的帮助)请大家指导

//................................
通过大家的帮助:
得到另一个写法,不会产生精度问题

(1+N)*N /2 - S = a + b
1/6 * n*(n + 1)*(2n + 1) - X = a*a + b*b

注:
1/6 * n*(n + 1)*(2n + 1)=1*1 + 2*2 + 3*3 +...+N*N
X = A[0]*A[0] + A[1]*A[1] +...A[N-3]*A[N-3]
 
==>
a + b = m
a*a + b*b = n

由于可解出a,b

    unsigned  int  sum  =   0 ;
    unsigned 
int  sqrSum  =   0 ;

    
for (i = 0 ; i < N - 2 ; i ++ )
    {
        sum 
+=  N - i - A[i];       
        sqrSum 
+=  ((N - i) * (N - i))  -  ((A[i]) * A[i]);
     
    }
    sum 
+=   2   +   1
    sqrSum 
+=   2 * 2   +   1 * 1 ;




你可能感兴趣的:(一道算法面试题,大家讨论看看)