部分面试题分析
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。【并查集】
输入
第一行包含两个整数N和K,后面N行每行三列,分别为x、y、z。
输出
最大的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: }