代码改变世界

部分面试题分析

2012-07-29 20:24  coodoing  阅读(394)  评论(0编辑  收藏  举报

1、两个数组a[N],b[N],其中A[N]的各个元素值已知,现给b[i]赋值,b[i] = a[0]*a[1]*a[2]...*a[N-1]/a[i];
要求

1.不准用除法运算
2.除了循环计数值,a[N],b[N]外,不准再用其他任何变量(包括局部变量,全局变量等)

3.满足时间复杂度O(n),空间复杂度O(1)

   1: private static int[] transform(int[] a, int[] b) {
   2:     int i = 0;
   3:     b[b.length - 1] = 1;
   4:     for (i = b.length - 2; i >= 0; i--)
   5:         b[i] = a[i + 1] * b[i + 1];
   6:     for (i = 1; i < b.length; i++)
   7:         a[i] = a[i] * a[i - 1];
   8:     for (i = 1; i < b.length; i++)
   9:         b[i] = b[i] * a[i - 1];
  10:     return b;
  11: }
  12:  
  13: private static int[] transform2(int[] a, int[] b) {
  14:     // S=A(0)*A(1)*A(2)……*A(N)
  15:     // B(I)=10lgS-lgA(I)
  16:     // java中math.pow函數有一定的誤差
  17:     int i;
  18:     b[0] = 1;
  19:     for (i = 0; i < a.length; i++)
  20:         b[0] *= a[i];
  21:     System.out.println("b[0]=" + b[0]);
  22:     for (i = a.length - 1; i >= 0; i--) {
  23:         b[i] = (int) Math.pow(10, (Math.log10(b[0]) - Math.log10(a[i])))+1;
  24:     }
  25:     return b;
  26: }

2、我们把只包含因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含因子7。习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第1500个丑数。

    最简单的肯定是遍历方法,但遍历法很大的问题在于对每个数都进行判断,进行取余和除的运算了,增加了算法的复杂度。另一种解决思路为:

      根据丑数的定义,丑数应该是另一个丑数乘以2、3或者5的结果(1除外)。因此我们可以创建一个数组,里面的数字是排好序的丑数。里面的每一个丑数是前面的丑数乘以2、3或者5得到的。那关键就是确保数组里的丑数是有序的了。我们假设数组中已经有若干个丑数,排好序后存在数组中。我们把现有的最大丑数记做M。现在我们来生成下一个丑数,该丑数肯定是前面某一个丑数乘以2、3或者5的结果。我们首先考虑把已有的每个丑数乘以2。在乘以2的时候,能得到若干个结果小于或等于M的。由于我们是按照顺序生成的,小于或者等于M肯定已经在数组中了,我们不需再次考虑;我们还会得到若干个大于M的结果,但我们只需要第一个大于M的结果,因为我们希望丑数是按从小到大顺序生成的,其他更大的结果我们以后再说。我们把得到的第一个乘以2后大于M的结果,记为M2。同样我们把已有的每一个丑数乘以3和5,能得到第一个大于M的结果M3和M5。那么下一个丑数应该是M2、M3和M5三个数的最小者。

   1: ArrayList<Integer> ugly = new ArrayList<Integer>();
   2: ugly.add(1);
   3: ugly.add(2);
   4: ugly.add(3);
   5: int max = 3;
   6: long start = System.currentTimeMillis();
   7: System.out.println(start);
   8: while (true) {
   9:     int m2 = 0;
  10:     for (Integer i : ugly) {
  11:         m2 = i * 2;
  12:         if (m2 > max)
  13:             break;
  14:     }
  15:     int m3 = 0;
  16:     for (Integer i : ugly) {
  17:         m3 = i * 3;
  18:         if (m3 > max)
  19:             break;
  20:     }
  21:     int m5 = 0;
  22:     for (Integer i : ugly) {
  23:         m5 = i * 5;
  24:         if (m5 > max)
  25:             break;
  26:     }
  27:     max = (m2 < m3 ? m2 : m3) < m5 ? (m2 < m3 ? m2 : m3) : m5;
  28:     ugly.add(max);
  29:     if (ugly.size() == 1500) {
  30:         System.out.println(max);
  31:         break;
  32:     }
  33: }
  34: long end = System.currentTimeMillis();
  35: long consuption = end - start;
  36: System.out.println("耗时:" + consuption + "ms");

另外其他几种解决方案可以参考:http://www.iteye.com/topic/832545。其中:

* 1.method1是最基础的遍历,唯一的优点估计就是简单易懂。<br/>
* 2.method2,method3的思想是先人工估算范围值,将一定范围内的值乘2,3,5排重增加,不同的地方在于method2重新遍历,
* method3排序求下标<br/>
* 3.method4的思想是将已经获取的值分别遍历,乘以2,3,5,当比最大值大就停止,比较这3个数的最小值,增加到定义的有序数组中。<br/>
* 4.method5的思想是将数进行评估,评估出该数包含丑数的数量,当超过丑数要求数量时,进行2分法进行缩小范围,直至求出解。

3、有N个网页(x_j-x_i)2 +(y_j-y_i)2 + (z_j-z_i)2。请求出最大的t,使得N个网页可以聚成K类,其中每个类至少包含一个网页,且任意两个位于不同类中网页的相似度都至少为t。并查集

输入

第一行包含两个整数NK,后面N行每行三列,分别为xyz

输出

最大的t的值,使用四舍五入在小数点后保留六位小数。

样例输入

5 3

0.1 0.2 0.4

0.2 0.8 0.7

0.3 0.4 0.5

0.0 0.5 0.0

0.3 0.3 0.2

样例输出

0.170000

   1: //二分+并查集
   2: #include <stdio.h>
   3: #include <iostream>
   4: #include <string.h>
   5: #include <set>
   6:  
   7: using namespace std;
   8:  
   9: const int maxn = 1024 ;
  10: int n , k , father[maxn] ;
  11: double diff[maxn][maxn] , x[maxn] , y[maxn] , z[maxn] , mind , maxd ;
  12: bool vis[maxn] ;
  13: const double precision = 1e-9 ;
  14:  
  15: inline double get_max(double mm,double nn) {    return mm > nn ? mm : nn ;    }
  16: inline double get_min(double mm,double nn) {    return mm < nn ? mm : nn ;    }
  17:  
  18: void myUnion(int i,int j)
  19: {
  20:     father[i] = j ;
  21: }
  22:  
  23: int find_anc(int i)    {    return father[i] == i ? i : ( father[i] = find_anc(father[i]) ) ;    }
  24:  
  25: bool check(double pos)
  26: {
  27:     int i , j , cnt ;
  28:     cnt = 1 ;
  29:     memset(vis,0,sizeof(vis));
  30:     for( i = 1 ; i <= n ; i++) father[i] = i ;
  31:     for ( i = 1 ; i <= n ; i++)
  32:     {
  33:         for( j = 1 ; j <= n ; j++) if( i != j )
  34:         {
  35:             if( diff[i][j] < pos ) myUnion(find_anc(i),find_anc(j));
  36:         }
  37:     }
  38:     int sth = 0 ;
  39:     for( i = 1 ; i <= n ; i++) 
  40:         if(!vis[j=find_anc(i)])  //j==5
  41:         {    
  42:             sth++;
  43:             vis[j] = 1 ;
  44:         }
  45:     return sth >= k ;
  46: }
  47:  
  48: void solve()
  49: {
  50:     int i , j  ;
  51:     double l , r , mid ;
  52:     l = mind ; r = maxd ;
  53:     while ( l <= r )
  54:     {
  55:         mid = ( l+r ) / 2.0 ;
  56:         //判断mid是否可以构成K个类..
  57:         if (check(mid)) l = mid+precision ;
  58:         else r = mid - precision ;
  59:     }
  60:     printf("%.6lf\n",r);
  61: }
  62:  
  63: int main()
  64: {
  65:     int i , j  ;
  66:     while (scanf("%d%d",&n,&k)!=EOF)
  67:     {
  68:         for ( i = 1 ; i <= n ; i++) scanf("%lf%lf%lf",&x[i],&y[i],&z[i]);
  69:         mind = 0.0, maxd = 1.0;
  70:         for( i = 1 ; i <= n ; i++)
  71:             for( j = i ; j <= n ; j++)
  72:             {
  73:                 diff[j][i] = diff[i][j] = (x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])+(z[i]-z[j])*(z[i]-z[j]);
  74:                 // mind = get_min(mind,diff[i][j]);
  75:                 // maxd = get_max(maxd,diff[i][j]);
  76:             }
  77:         solve();
  78:     }
  79: }