面试题总结

1. 求一个矩阵中最大的二维矩阵(元素和最大) (solved)

思路类似于一维数据中求最大和的问题。。。。 


2.无向图中挂接点的计算 (solved)

使用dfs算法,关键在于low(w)是以w为根的子树中所有定点的最小值,或者是反向边的最小值。

http://www.ibluemojo.com/school/articul_algorithm.html

附加的还有强连通子图,无向图中桥的计算,使用的都是基于DFS的方法。 


3.     微软的链表系列题目(solved)

  a. 判断一个链表是否有环?用两个指针,一个步进为1,一个步进为2,若有环,必相交!

  b. 判断链表是否相交?

  c. 找到链表相交的节点



4.     写出第1500个丑数~ (solved)



5.     求两个串中的第一个最长子串(suffix tree, solved)

 

6.     1024!的末尾有多少0?(solved)

  2*5=10,所以取决于2,5因子的个数



7.  有6种不同颜色的球,分别记为1,2,3,4,5,6,每种球有无数个。现在取5个球,求在以下的条件下:

     1、5种不同颜色

     2、4种不同颜色的球

     3、3种不同颜色的球

     4、2种不同颜色的球

它们的概率。


8.      题目大意如下:

一排N(最大1M)个正整数+1递增,乱序排列,第一个不是最小的,把它换成-1,
最小数为a且未知求第一个被-1替换掉的数原来的值,并分析算法复杂度。(solved)

9.  歌德巴赫猜想说任何一个不小于6的偶数都可以分解为两个奇素数之和。

对此问题扩展,如果一个整数能够表示成两个或多个素数之和,则得到一个素数和分解式。

对于一个给定的整数,输出所有这种素数和分解式。
注意,对于同构的分解只输出一次(比如5只有一个分解2 + 3,而3 + 2是2 + 3的同构分解式

)。

例如,对于整数8,可以作为如下三种分解:
(1) 8 = 2 + 2 + 2 + 2
(2) 8 = 2 + 3 + 3
(3) 8 = 3 + 5

注意,素数属于集合(i,end)


10.   输入a1,a2,...,an,b1,b2,...,bn, 
  在O(n)的时间,O(1)的空间将这个序列顺序改为a1,b1,a2,b2,a3,b3,...,an,bn,
  且不需要移动,通过交换完成,只需一个交换空间。 

解法:交叉换位,以2的次幂增加移动块的大小 


11.     创新工场面试题:abcde五人打渔,打完睡觉,a先醒来,扔掉1条鱼,把剩下的分成5分,拿一份走了;b再醒来,也扔掉1条,把剩下的分成5份,拿一份走了;然后cde都按上面的方法取鱼。问他们一共打了多少条鱼(solved)

 

12.     搜狗笔试题:一个长度为n的数组a[0],a[1],...,a[n-1]。现在更新数组的名个元素,即a[0]变为a[1]到a[n-1]的积,a[1]变为a[0]和a[2]到a[n-1]的积,...,a[n-1]为a[0]到a[n-2]的积(就是除掉当前元素,其他所有元素的积)。程序要求:具有线性复杂度,且不能使用除法运算符 (solved)

解法是用两个数组,分别存储两个方向的乘积!

 

13.     腾讯面试题:给你5个球,每个球被抽到的可能性为30、50、20、40、10,设计一个随机算法,该算法的输出结果为本次执行的结果。输出A,B,C,D,E即可。(solved)


14.     有无序的实数列V[N],要求求里面大小相邻的实数的差的最大值,关键是要求线性空间和线性时间 (solved)

 线性时间排序:要不计数,要么桶!

 其实这个问题要求线性时间条件下,通常会让我们想到桶排序;接着关键是考虑怎么减少桶排序中对桶中各数的排序即可想到解决方法。我的算法如下:

  1. 主要是先找出最大的数与最小的数,然后构造一个n个桶,桶的下标与数的关系为: index = (v[i]-min)/(max-min/n).
  2. 遍历数列,将数值插入到对应的桶中。每个桶最多保留最小和最大的两个元素,不需要多余的数。
  3. 遍历所有的桶,记录每个桶之间有多少个空桶到数据flags中,并求出最大连续空桶数 maxGap。
  4. 最后遍历flags数组,对于空桶数 >= maxGap -1 的元素,计算从前面的最近的不为空的桶中的大元素与当前桶中的最小元素的差,最终找出最大差

 


15.     25匹赛马,5个跑道,也就是说每次有5匹马可以同时比赛。问最少比赛多少次可以知道跑得最快的5匹马 (solved)


16.     Alibaba笔试题:给定一段产品的英文描述,包含M个英文字母,每个英文单词以空格分隔,无其他标点符号;再给定N个英文单词关键字,请说明思路并编程实现方法

    String extractSummary(String description,String[] key words)

目标是找出此产品描述中包含N个关键字(每个关键词至少出现一次)的长度最短的子串,作为产品简介输出。(不限编程语言)20分。(扫描过程始终保持一个[left,right]的range,初始化确保[left,right]的range里包含所有关键字则停止。然后每次迭代:

     a.     试图右移动left,停止条件为再移动将导致无法包含所有关键字。

     b.     比较当前range's length和best length,更新最优值。

     c.     右移right,停止条件为使任意一个关键字的计数+1。

     d.     重复迭代。 (solved) 

 

 17.     阿里云笔试题:一个HTTP服务器处理一次请求需要500毫秒,请问这个服务器如何每秒处理100个请求


18.     输入两个整数A和B,输出所有A和B之间满足指定条件的数的个数。指定条件:假设C=8675在A跟B之间,若(8+6+7+5)/ 4 > 7,则计一个,否则不计。要求时间复杂度:log(A)+log(B)  <unsolved>


19.     旅行商问题 <unsolved>


20.如何利用一个能够返回[0,1]平均随机点的函数,等概率地生成一个单位圆中的点,使得生成地点在圆内的分布概率尽量平均,即在面积上平均分布。

  1. 随机产生[0, 360]上的一个角度θ
  2. 随机产生 [0, r^2] 上的一个半径的平方 r^2,

这个点(θ, r)就是一个随机的圆上的点

21.     为分析用户行为,系统常需存储用户的一些query,但因query非常多,故系统不能全存,设系统每天只存m个query,现设计一个算法,对用户请求的query进行随机选择m个,请给一个方案,使得每个query被抽中的概率相等,并分析之,注意:不到最后一刻,并不知用户的总请求量。( solved)

 

22.     四个线程t1,t2,t3,t4,向4个文件中写入数据,t1只能写入1,t2只能写入2,t3只能写入3,t4只能写入4,对4个文件A,B,C,D写入如下内容
A:123412341234.....
B:234123412341....
C:341234123412....
D:412341234123....
怎么实现同步可以让线程并行工作?

23.     12个工厂分布在一条东西向高速公路的两侧,工厂距离公路最西端的距离分别是0、4、5、10、12、18、27、30、31、38、39、47.在这12个工厂中选取3个原料供应厂,使得剩余工厂到最近的原料供应厂距离之和最短,问应该选哪三个厂 ? 


24.     平均要取多少个(0,1)中的随机数才能让和超过1(e)<solved>


25.     用两个栈实现一个队列!

 


class List{

  private:

  Stack a,b;

  List::push(_a){

    b.push(_a);

  }


  List::pop(){

    if(a.empty()){

      while(!b.empty()){

        a.push(b.pop())

      }

    }

  }

  return a.pop()

};

因此最好是让一个栈用来压入,另一个用来弹出!!! 

 

26.     假设你有一个用1001个整数组成的数组,这些整数是任意排列的,但是你知道所有的整数都在1到1000(包括1000)之间。此外,除一个数字出现两次外,其他所有数字只出现一次。假设你只能对这个数组做一次处理,用一种算法找出重复的那个数字。如果你在运算中使用了辅助的存储方式,那么你能找到不用这种方式的算法吗? <solved>

a. 对数组求和,再减去(1+1000)*1000/2,即为多出来的数。

b.  使用异或方法!!!

// a ^ a ^ b = b


//1001个介于1、1000之间的整数,再加上下标,正好有一个数字出现三次,其余出现两次,妙

int find( int a[], int size){

        int k=a[0];

        for(int i=1; i<=1000; ++i){

                k ~= a[i] ~ i;

        }

        return k;

}



27.     (solved)写一个函数,交换两个参数,要求不使用临时变量

这是一个老题目了,大概有三种解法:

  • 异或(比较完美)?
  • void exchange(int &a, int &b) {    a = a ^ b;    b = a ^ b;    a = a ^ b;}

  • 加减(容易溢出)?
  • void exchange(int &a, int &b) {    a = a + b;    b = a - b;    a = a - b;}

  • 乘除(超级容易溢出)?
  • void exchange(int &a, int &b) {    a = a * b;    b = a / b;    a = a / b;}
    2、不用判断,不用循环,不用乘除法,不用?:,不用switch,求1+2+…+n(n为参数)

不能用乘法,所以就不能用等差数列的公式n*(n+1)/2了,不能用循环,那么迭代的算法就不能用了。那么我就想到了递归,但是递归要有判断条件,而我们的题目不让永判断语句(包括?:),那怎么办呢?

  • &&(考虑到&&的截断性,隐式的判断)?
  • int sum(int n) {    int r = 0;    n && (r = n + sum(n - 1));    return r;}

  • ||(考虑到||的阶段性,隐式判断)?
  • int sum(int n) {    int r = 0;    !n || (r = n + sum(n - 1));    return r;}

  • 利用类的构造函数(缺点:浪费空间)?
  • 1
    2
    3
    4
  • class sum_helper {private:    static int s;    static int n;public:    sum_helper() {        s += n++;    }    static int get_sum() {        return s;    }    static void reset() {        s = 0;        n = 1;    }};
     
    int sum_helper::s = 0;int sum_helper::n = 1;
     
    int sum2(int n) {    sum_helper::reset();    delete[] (new sum_helper[n]);    return sum_helper::get_sum();}

  • n写成二进制的形式,101010....0,那么n ^ 2, 则可以写成n( ai * 2^i + ... + aj * 2 ^ j + ... ), 1 + 2 + ... + n = n(n+1)/2 = (n^2 + n)/2; #define T(X, Y, i) ( ( Y & 1 << i) && (X += Y << i)) ;  r= n; T(r, n, 0); T(r, n,1); .... T(r, n, 31);

3、不用循环判断一个数是否是2的整数冪

考虑2^k与2^k-1的二进制特点,2^k的二进制中只有第k(从0开始)位是1,其余是0,那么2^k-1呢?0…k-1为1,其余位为0,所以判断方法很简单了:

判断n&(n-1)是否为0,为0说明是2的整数冪,否则不是

问题扩展:判断一个数是否是4的整数冪,扩展的问题可以分成判断这个数是不是2的整数冪+判断这个数是不是完全平方数

判断一个数是否是是完全平方数,考虑1+3+…+(2n-1)=n^2,所以我们就可以将这个数减去1,3…知道小于或等于0,如果最终结果是0,那么就是完全平方数,否则不是

 4、求1^2+2^3+…+n^2,要求不用循环,不用判断

记得以前学过一个公式吧:1^2+2^3+…+n^2=n(n+1)(2n+1)/6

 5、找出两个数种较大的一个,要求不用比较运算

int getMax(int a, int b) {

?

1

2

3

4

5

    int c = a - b;

    int k = (c >> 31) & 0x1;

    int max = a - k * c;

    return max;

}

28.     约瑟夫环问题

我们知道第一个人编号一定是(m - 1)%n, 出列之后,剩下的n-1个人组成了一个新的约瑟夫环(以编号为k=m%n的人开始):    

k   k+1   k+2   ... n-2, n-1, 0, 1, 2, ... k-2 并且从k开始报0。 现在我们把他们的编号做一下转换: k      --> 0 k+1    --> 1 k+2    --> 2 ... ... k-2    --> n-2 k-1    --> n-1 变换后就完完全全成为了(n-1)个人报数的子问题,假如我们知道这个子问题的解:例如x是最终的胜利者,那么根据上面这个表把这个x变回去不刚好就是n个人情况的解吗?!!变回去的公式很简单,相信大家都可以推出来:x'=(x+k)%n (x' 为n个人报数的解) 如何知道(n-1)个人报数的问题的解?对,只要知道(n-2)个人的解就行了。(n-2)个人的解呢?当然是先求(n-3)的情况 ---- 这显然就是一个倒推问题!好了,思路出来了,下面写递推公式: 令f[i]表示i个人玩游戏报m退出最后胜利者的编号,最后的结果自然是f[n] 递推公式 f[1]=0; f[i]=(f[i-1]+m)%i;   (i>1) 有了这个公式,我们要做的就是从1-n顺序算出f[i]的数值,最后结果是f[n]。因为实际生活中编号总是从1开始,我们输出f[n]+1 

 

 29.     题目:输入一个正数n,输出所有和为n连续正数序列。(直接计算出i和j, <solved> )

( i + ... +j = (j-i+1)*(i+j)/2 == n )



30.     平面上N个点,每两个点都确定一条直线,求出斜率最大的那条直线所通过的两个点(斜率不存在的情况不考虑)。时间效率越高越好。


31.     有5个海盗,按照等级从5到1排列,最大的海盗有权提议他们如何分享100枚金币。但其他人要对此表决,如果多数反对,那他就会被杀死。他应该提出怎样的方案,既让自己拿到尽可能多的金币又不会被杀死?


32.  请定义一个宏,比较两个数a、b的大小,不能使用大于、小于、if语句

答案如下: #define Max(a,b) (a==b)?e:(((a-b)|1<<31)==(a-b)?b:a)  

1<<31   : 00000000000001左移31位至最高位,变为1000000000000000000000,而(a-b)可能是正数或者负数或者0,规定:有符号型数据储存在内存中时,最高一位用来储存符号,剩下的位用来储存数据,如果是负数,最高位就是1,如果是正数,最高位就是0。那么:如果(a-b)为负数,则最高位是1 它们按位与的结果是(a-b) 恒等,输出b。

#define max(a,b) (((a-b)>>31)|0)?b:a

比较简洁和完全的定义是: #define Max(a,b) (a==b)?e:((((a-b)>>31)|0)?b:a)



33.  题目:10个房间里放着随机数量的金币。每个房间只能进入一次,并只能在一个房间中拿金币。一个人采取如下策略:前四个房间只看不拿。随后的房间只要看到比前四个房间都多的金币数,就拿。否则就拿最后一个房间的金币。计算成功的概率!!!(solved)

<分为两部分,一部分是在i的概率,一部分是前i-1个最大的,在k个的概率>

 

34.  一个含n个元素的整数数组至少存在一个重复数,请编程实现,在O(n)时间内找出其中任意一个重复数。

<耗费空间>

<使用类似于计数排序的方法>

<solved>


35.  求最大重叠区间大小,(可以考虑求最大重叠区间的个数)<solved>

题目描述:请编写程序,找出下面“输入数据及格式”中所描述的输入数据文件中最大重叠区间的大小。 对一个正整数 n ,如果n在数据文件中某行的两个正整数(假设为A和B)之间,即A<=n<=B或A>=n>=B ,则 n 属于该行;如果 n 同时属于行i和j ,则i和j有重叠区间;重叠区间的大小是同时属于行i和j的整数个数。例如,行(10 20)和(12 25)的重叠区间为 [12 20] ,其大小为9,行(20 10)和( 20 30 )的重叠区间大小为 1 。

ans:首先按照起点排序,一个区间跟前面所有区间交集的最大值

 

36.  假设有一颗二叉树,已知这棵树的节点上不均匀的分布了若干石头,石头数跟这棵二叉树的节点数相同,石头只可以在子节点和父节点之间进行搬运,每次只能搬运一颗石头。请问如何以最少的步骤将石头搬运均匀,使得每个节点上的石头上刚好为1。



37.  N个鸡蛋放到M个篮子中,篮子不能为空,要满足:对任意不大于N的数量,能用若干个篮子中鸡蛋的和表示。



38.  有一台机器,上面有m个储存空间。然后有n个请求,第i个请求计算时需要占 R[i]个空间,储存计算结果则需要占据O[i]个空间(据O[i]个空间(其中O[i]<R[i])。问怎么安排这n个请求的顺序,使得所有请求都能完成。你的算法也应该能够判断出无论如何都不能处理完的情况。比方说,m=14,n=2,R[1]=10,O[1]=5,R[2]=8,O[2]=6。在这个例子中,我们可以先运行第一个任务,剩余9个单位的空间足够执行第二个任务;但如果先走第二个任务,第一个任务执行时空间就不够了,因为10>14-6。<银行家算法!!!>


39.  字典序排列!!!

字典序列算法是一种非递归算法。而它正是STL中Next_permutation的实现算法。我们来看看他的思路吧:
它的整体思想是让排列成为可递推的数列,也就是说从前一状态的排列,可以推出一种新的状态,直到最终状态。比如说,最初状态是12345,最终状态是54321。其实我觉得这跟我们手动做全排列是一样的。首先是12345,然后12354,然后12435,12453....逐渐地从后往前递增。

看看算法描述:
    首先,将待排序列变成有序(升序)序列。然后,从后向前寻找,找到相邻的两个元素,Ti<Tj,(j=i+1)。如果没有找到,则说明整个序列已经是降序排列了,也就是说到达最终状态54321了。此时,全排列结束。

    接着,如果没有结束,从后向前找到第一个元素Tk,使得Tk>Ti(很多时候k=j),找到它,交换Ti跟Tk,并且将Tj到Tn(Tn是最后一个元素)的子序列进行倒置操作。输出此序列。并回到第二步继续寻找ij.

例如839647521是数字1~9的一个排列。从它生成下一个排列的步骤如下:
  自右至左找出排列中第一个比右边数字小的数字4    839647521
  在该数字后的数字中找出比4大的数中最小的一个5    839647521
  将5与4交换 839657421
  将7421倒转 839651247
  所以839647521的下一个排列是839651247。
  839651247的下一个排列是839651274。


40.  如何求根号2的值,并且按照我的需要列出指定小数位<二分法>


41.  1分2分5分的硬币,组成1角,共有多少种组合

<如果求最少的硬币数,可以使用动态规划>

<也可以使用动态规划的方法>

<x + 2*y + 5*z = 10 ==>  5*z = 10 - x - 2*y ;对于z的不同取值,只要给出剩下的钱,可以用多少1,2分的钱表示>

<solved>


42.  在人人好友里,A和B是好友,B和C是好友,如果A 和C不是好友,那么C是A的二度好友,在一个有10万人的数据库里,如何在时间0(n)里,找到某个人的十度好友<BFS><solved>


43.  有一个函数int getNum(),每运行一次可以从一个数组V[N]里面取出一个数,N未知,当数取完的时候,函数返回NULL。现在要求写一个函数int get(),这个函数运行一次可以从V[N]里随机取出一个数,而这个数必须是符合1/N平均分布的,也就是说V[N]里面任意一个数都有1/N的机会被取出,要求空间复杂度为O(1)<hard>


44.  有N个正实数(注意是实数,大小升序排列) x1 , x2 ... xN,另有一个实数M。 需要选出若干个x,使这几个x的和与 M 最接近。 请描述实现算法,并指出算法复杂度<如果是正整数,那么可以用背包问题动态规划解>

<现在,可以使用背包问题递归解,排序用于做趋势判断而已>


45.  五笔的编码范围是a ~ y的25个字母,从1位到4位的编码,如果我们把五笔的编码按字典序排序,形成一个数组如下:

a, aa, aaa, aaaa, aaab, aaac, … …, b, ba, baa, baaa, baab, baac … …, yyyw, yyyx, yyyy

其中a的Index为0,aa的Index为1,aaa的Index为2,以此类推。

1)编写一个函数,输入是任意一个编码,比如baca,输出这个编码对应的Index;

2)编写一个函数,输入是任意一个Index,比如12345,输出这个Index对应的编码。

(注意编码的变化范围a-y, aa-ay, aaa-aay, aaaa-aaay!!!)

(solved)


46.  Q:有这样一种编码:如,N=134,M=f(N)=143,N=020,M=fun(N)=101,其中N和M的位数一样,N,M可以均可以以0开头,N,M的各位数之和要相等,即1+3+4=1+4+3,且M是大于N中最小的一个,现在求这样的序列S,N为一个定值,其中S(0)=N,(1)=fun(N),S(2)=fun(S(1)) 

<注意,如果是299怎么办?从右向左,找到第一个正数,再往下找到第一个小于9的数组,然后考虑加1,选择用剩下的数组成最小的数>


47.  对已排好序的数组A,一般来说可用二分查找可以很快找到。现有一特殊数组A[],它是循环递增的,如A[]={ 17 19 20 25 1 4 7 9},试在这样的数组中找一元素x,看看是否存在。这个问题需要判断在那个区间之中!(solved , 如果a[m] > a[l],则数组前半部分有序,否则后半部分有序 )


48.  一个大小为N的数组,里面是N个整数,怎样去除重复,要求时间复杂度为O(n),空间复杂度为O(1) (solved)


49.  将一个较大的钱,不超过1000000(10^6)的人民币,兑换成数量不限的100、50、10、5、2、1的组合,请问共有多少种组合呢?

(背包?)


50.  今天完美10.16笔试题:2D平面上有一个三角形ABC,如何从这个三角形内部随机取一个点,且使得在三角形内部任何点被选取的概率相同。(考虑一边AB的高h,产生0-1的随机数r, 然后 r*(h^2),则选中垂线上的一点,通过这一点做平行于底边的直线,随机选择一点)


57.      How will you implement a stack using a priority queue. Push and pop should be in O(1).

posted @ 2012-07-27 16:27  追风人  阅读(963)  评论(0编辑  收藏  举报