一些笔试题

微策略

http://blog.youkuaiyun.com/hackbuteer1/article/details/6889217

1、8*8的棋盘上面放着64个不同价值的礼物,每个小的棋盘上面放置一个礼物(礼物的价值大于0),一个人初始位置在棋盘的左上角,每次他只能向下或向右移动一步,并拿走对应棋盘上的礼物,结束位置在棋盘的右下角,请设计一个算法使其能够获得最大价值的礼物。

[cpp]  view plain copy
  1. //经典的动态规划  
  2. //dp[i][j] 表示到棋盘位置(i,j)上可以得到的最大礼物值  
  3. //dp[i][j] = max( dp[i][j-1] , dp[i-1][j] ) + value[i][j]  (0<i,j<n)  
  4.   
  5. int i, j, n = 8;  
  6. dp[0][0] = value[0][0];  
  7. for( i = 1 ; i < n ; i++ )  
  8. {  
  9.     dp[i][0] = dp[i-1][0] + value[i][0];  
  10. }  
  11. for( j = 1 ; j < n ; j++ )  
  12. {  
  13.     dp[0][j] = dp[0][j-1] + value[0][j];  
  14. }  
  15.   
  16. for( i = 1 ; i < n ; i++ )  
  17. {  
  18.     for( j = 1 ; j < n ; j++ )  
  19.     {  
  20.         dp[i][j] = max( dp[i][j-1] , dp[i-1][j] ) + value[i][j];  
  21.     }  
  22. }  
  23. cout<<dp[n-1][n-1]<<endl;  

扩展:现在增加一个限定值limit,从棋盘的左上角移动到右下角的时候的,每次他只能向下或向右移动一步,并拿走对应棋盘上的礼物,但是拿到的所有的礼物的价值之和不大于limit,请设计一个算法请实现。

[cpp]  view plain copy
  1. int row,col;  
  2. int limit;  
  3. int dp[row][col][limit];  
  4.   
  5. int getMaxLessLimit()  
  6. {  
  7.     memset(dp,0,sizeof(dp));  
  8.     for(int r = row-1 ; r >= 0; r--)  
  9.     {  
  10.         for(int c = col-1 ; c >= 0; c--)  
  11.         {  
  12.             for(int l = 0 ; l <= limit; l++)  
  13.             {  
  14.                 if(l >= matrix[r][c])  
  15.                 {  
  16.                     int max = 0;  
  17.                     if(r != row-1 && dp[r+1][c][l-matrix[r][c]]>max)  
  18.                         max = dp[r+1][c][l-matrix[r][c]];  
  19.                     if(c != col-1 && dp[r][c+1][l-matrix[r][c]]>max)  
  20.                         max = dp[r][c+1][l-matrix[r][c]];  
  21.                     if(max == 0 && !(r == row-1 && c == col-1))  
  22.                         dp[r][c][l] = 0;  
  23.                     else  
  24.                         dp[r][c][l] = max + matrix[r][c];  
  25.                 }  
  26.             }  
  27.         }  
  28.     }  
  29.     return dp[0][0][limit];  
  30. }  

或者

[cpp]  view plain copy
  1. int hash[row][col][limit];  
  2. int getMaxLessLimit()  
  3. {  
  4.     memset(hash,0,sizeof(hash));  
  5.     hash[0][0][matrix[0][0]] = 1;  
  6.     for(int i = 0 ; i < row ; i++)  
  7.     {  
  8.         for(int j = 0 ; j < col ; j++)  
  9.         {  
  10.             for(int k = 0 ; k <= limit ; k++)  
  11.             {  
  12.                 if(k >= matrix[i][j])  
  13.                 {  
  14.                     if(i >= 1 && hash[i-1][j][k-matrix[i][j]])  
  15.                         hash[i][j][k] = 1;  
  16.                     if(j >= 1 && hash[i][j-1][k-matrix[i][j]])  
  17.                         hash[i][j][k] = 1;  
  18.                 }  
  19.             }  
  20.         }  
  21.     }  
  22.     int ans = 0;  
  23.     for(int k = limit; k >= 0; k--)  
  24.     {  
  25.         if(hash[row-1][col-1][k] && k>ans)  
  26.             ans = k;  
  27.     }  
  28.     return ans;  
  29. }  

2、有两个字符串s1和s2,其长度分别为l1和l2,将字符串s1插入到字符串s2中,可以插入到字符串s1的第一个字符的前面或者最后一个字符的后面,对于任意两个字符串s1和s2,判断s1插入到s2中后是否能够构成回文串。。

3、已知有m个顶点,相邻的两个顶点之间有一条边相连接,首位顶点也有一条边连接,这样就构成了一个圆环。
现在有一个二维数组M[][],M[i][j]=1时,表明第i和j个节点之间有条边存在,M[i][j]=0时,表明第i和j个节点之间没有边存在,其中 M[i][i]=0,M[i][j]=M[j][i],输入为一个二维数组M[][]和顶点的个数n,试着判断该图中是否存在两个圆环,且两个圆环彼此之间没有公共点。试着实现下面这个函数:
bool IsTwoCircle(int **M,int n)
{
  ......
}

4、给定如下的n*n的数字矩阵,每行从左到右是严格递增, 每列的数据也是严格递增

1 3 7 15 16

2 5 8 18 19

4 6 9 22 23
10 13 17 24 28
20 21 25 26 33
现在要求设计一个算法, 给定一个数k 判断出k是否在这个矩阵中。 描述算法并且给出时间复杂度(不考虑载入矩阵的消耗)

方法一
从右上角开始(从左下角开始也是一样的),然后每步往左或往下走。

这样每步都能扔掉一行或者一列,最坏的情况是被查找的元素位于另一个对角,需要2N步,因此这个算法是o(n)的,而且代码简洁直接。

[cpp]  view plain copy
  1. bool stepWise(int mat[][N] , int key , int &row , int &col)  
  2. {  
  3.     if(key < mat[0][0] || key > mat[N-1][N-1])  
  4.         return false;  
  5.     row = 0;  
  6.     col = N-1;  
  7.     while(row < N && col >= 0)  
  8.     {  
  9.         if(mat[row][col] == key )     //查找成功  
  10.             return true;  
  11.         else if(mat[row][col] < key )  
  12.             ++row;  
  13.         else  
  14.             --col;  
  15.     }  
  16.     return false;  
  17. }  
方法二(分治法)
首先,我们注意到矩阵中的元素总是把整个矩阵分成四个更小的矩阵。例如,中间的元素9把整个矩阵分成如下图所示的四块。由于四个小矩阵也是行列有序的,问题自然而然地划分为四个子问题。每次我们都能排除掉四个中的一个子问题。假如我们的查找目标是21,21>9,于是我们可以立即排除掉9左上方的那块,因为那个象限的元素都小于或等于9。

以下是这种二维二分的代码,矩阵的维度使用l、u、r、d刻画的,其中l和u表示左上角的列和行,r和d表示右下角的列和行。
[cpp]  view plain copy
  1. bool quadPart(int mat[][N] , int key , int l , int u , int r , int d , int &row , int &col)  
  2. {  
  3.     if(l > r || u > d)  
  4.         return false;  
  5.     if(key < mat[u][l] || key > mat[d][r])  
  6.         return false;  
  7.     int mid_col = (l+r)>>1;  
  8.     int mid_row = (u+d)>>1;  
  9.     if(mat[mid_row][mid_col] == key)     //查找成功  
  10.     {  
  11.         row = mid_row;  
  12.         col = mid_col;  
  13.         return true;  
  14.     }  
  15.     else if(l == r && u == d)  
  16.         return false;  
  17.   
  18.     if(mat[mid_row][mid_col] > key)  
  19.     {   // 分别在右上角、左上角、左下角中查找  
  20.         return quadPart(mat , key , mid_col+1 , u , r , mid_row , row , col) ||  
  21.                quadPart(mat , key , l , mid_row+1 , mid_col , d , row , col) ||  
  22.                quadPart(mat , key , l , u , mid_col , mid_row , row , col) ;  
  23.     }  
  24.     else  
  25.     {   // 分别在右上角、左下角、右下角中查找  
  26.         return quadPart(mat , key , mid_col+1 , u , r , mid_row , row , col) ||  
  27.                quadPart(mat , key , l , mid_row+1 , mid_col , d , row , col) ||  
  28.                quadPart(mat , key , mid_col+1 , mid_row+1 , r , d , row , col) ;  
  29.     }  
  30. }  
  31.   
  32. bool quadPart(int mat[][N] , int key , int &row , int &col)  
  33. {  
  34.     return bool quadPart(mat , key , 0 , 0 , N-1 , N-1 , row , col);  
  35. }  
5、设 一个64位整型n,各个bit位是1的个数为a个. 比如7, 2进制就是 111, 所以a为3。

现在给出m个数, 求各个a的值。要求代码实现。

思路:如果可以直接用stl的bitset。算法可用移位和&1来做。还有一个更好的算法是直接位与(x-1)直到它为0。

[cpp]  view plain copy
  1. while(n)  
  2. {  
  3.     n = n & (n-1);  
  4.     ++count;  
  5. }  

6、有N+2个数,N个数出现了偶数次,2个数出现了奇数次(这两个数不相等),问用O(1)的空间复杂度,找出这两个数,不需要知道具体位置,只需要知道这两个值。
       求解:如果只有一个数出现过奇数次,这个就比较好求解了,直接将数组中的元素进行异或,异或的结果就是只出现过奇数次的那个数。
      但是题目中有2个数出现了奇数次?,求解方法如下:
      假设这两个数为a,b,将数组中所有元素异或结果x=a^b,判断x中位为1的位数(注:因为a!=b,所以x!=0,我们只需知道某一个位为1的位数k,例如0010 1100,我们可取k=2或者3,或者5),然后将x与数组中第k位为1的数进行异或,异或结果就是a,b中一个,然后用x异或,就可以求出另外一个。
      为什么呢?因为x中第k位为1表示a或b中有一个数的第k位也为1,假设为a,我们将x与数组中第k位为1的数进行异或时,也就是将x与a外加上其他第k位为1的出现过偶数次的数进行异或,化简即为x与a异或,结果是b。
     代码如下:

[cpp]  view plain copy
  1. void getNum(int a[],int length)  
  2. {  
  3.     int s = 0;//保存异或结果  
  4.     for(int i=0;i<length;i++)  
  5.     {  
  6.         s=s^a[i];  
  7.     }  
  8.     int temp1 = s;     //临时保存异或结果  
  9.     int temp2 = s;     //临时保存异或结果  
  10.     int k=0;  
  11.     while((temp1&1) == 0)        //求异或结果中位为1的位数  
  12.     {  
  13.         temp1 = temp1>>1;  
  14.         k++;  
  15.     }  
  16.     for(int i=0;i<length;i++)  
  17.     {  
  18.         if((a[i]>>k)&1)          //将s与数组中第k位为1的数进行异或,求得其中一个数  
  19.         {  
  20.             //cout<<a[i]<<" ";  
  21.             s=s^a[i];  
  22.         }  
  23.     }  
  24.     cout<<s<<" "<<(s^temp2)<<endl;             //(s^temp2)用来求另外一个数  
  25. }  

7、找出数组中只出现一次的3个数。

思路类似于求解上题,关键是找出第一个来,然后借助上题结论求另外两个。 

a[]数组,假设x y z为只出现一次的数,其他出现偶数次
s^=a[i] 则x^y x^z y^z 的lowbit 这三个值有一个规律,其中肯定两个是一样的,另外一个是不一样的。令flips=上述三个值的异或。因此,可以利用此条件获得某个x(或者y,或者z),循环判断的条件是 a[i]^s的lowbit==flips
解释:a[i]^s即可划分为两组,一组是lowbit与flips不同,一组是lowbit与flips相同。这样就能找到某个x,y,z,找出后,与数组最户一个值交换,利用find2,找出剩余两个。

lowbit为某个数从右往左扫描第一次出现1的位置。其实 lowbit 函数里面写成  mark = (x&(x-1))^x  ; return mark ; 也是可以的,功能是一样的。

[cpp]  view plain copy
  1. /**   
  2. ** author :hackbuteer 
  3. ** date   :2011-10-19    
  4. **/  
  5. #include <iostream>    
  6. using namespace std;  
  7.   
  8. int lowbit(int x)  
  9. {  
  10.     return x & ~(x - 1);  
  11. }  
  12.   
  13. void Find2(int seq[], int n, int& a, int& b)  
  14. {  
  15.     int i, xors = 0;  
  16.     for(i = 0; i < n; i++)  
  17.         xors ^= seq[i];  
  18.   
  19.     int diff = lowbit(xors);  
  20.   
  21.     a = 0,b = 0;  
  22.     for(i = 0; i < n; i++)  
  23.     {  
  24.         if( diff&seq[i] )    //与运算,表示数组中与异或结果位为1的位数相同  
  25.             a ^= seq[i];  
  26.         else  
  27.             b ^= seq[i];  
  28.     }  
  29. }  
  30.   
  31. //三个数两两的异或后lowbit有两个相同,一个不同,可以分为两组  
  32. void Find3(int seq[], int n, int& a, int& b, int& c)  
  33. {  
  34.     int i, xors = 0;  
  35.     for(i = 0; i < n; i++)  
  36.         xors ^= seq[i];  
  37.   
  38.     int flips = 0;  
  39.     for(i = 0; i < n; i++)            //因为出现偶数次的seq[i]和xors的异或,异或结果不改变  
  40.         flips ^= lowbit(xors ^ seq[i]);  
  41.     //表示的是:flips=lowbit(a^b)^lowbit(a^c)^lowbit(b^c)  
  42.     //flips = lowbit(flips);    这个是多余的  
  43.   
  44.     //三个数两两异或后lowbit有两个相同,一个不同,可以分为两组  
  45.     //所以flips的值为:lowbit(a^b) 或 lowbit(a^c) 或 lowbit(b^c)  
  46.   
  47.   
  48.     //得到三个数中的一个  
  49.     a = 0;  
  50.     for(i = 0; i < n; i++)  
  51.     {  
  52.         if(lowbit(seq[i] ^ xors) == flips)     //找出三个数两两异或后的lowbit与另外两个lowbit不同的那个数  
  53.             a ^= seq[i];  
  54.     }  
  55.   
  56.     //找出后,与数组中最后一个值交换,利用Find2,找出剩余的两个  
  57.     for(i = 0; i < n; i++)  
  58.     {  
  59.         if(a == seq[i])  
  60.         {  
  61.             int temp = seq[i];  
  62.             seq[i] = seq[n - 1];  
  63.             seq[n - 1] = temp;  
  64.         }  
  65.     }  
  66.   
  67.     //利用Find2,找出剩余的两个  
  68.     Find2(seq, n - 1, b, c);  
  69. }  
  70. //假设数组中只有2、3、5三个数,2与3异或后为001,2与5异或后为111,3与5异或后为110,  
  71. //则flips的值为lowbit(110)= 2 ,当异或结果xors与2异或的时候,得到的就是3与5异或的结果110,其lowbit值等于flips,所以最先找出来的是三个数中的第一个数:2  
  72.   
  73. int main(void)  
  74. {  
  75.     int seq[]={ 2,3,3,2,4,6,4,10,9,8,8 };  
  76.     int a,b,c;  
  77.     Find3(seq, 11, a, b, c);  
  78.     cout<<a<<endl;  
  79.     cout<<b<<endl;  
  80.     cout<<c<<endl;  
  81.     return 0;  
  82. }  

8、do while(0)在宏定义中的应用。

看linux源码时,经常发现有宏定义用
#define XYZ \
do{...} while(0)
这是一个奇怪的循环,它根本就只会运行一次,为什么不去掉外面的do{..}while结构呢?原来这也是非常巧妙的技巧。在工程中可能经常会引起麻烦,而上面的定义能够保证这些麻烦不会出现。下面是解释:

假设有这样一个宏定义

#define macro(condition) \

if(condition) dosomething()

现在在程序中这样使用这个宏:

if(temp)
    macro(i);
else
    doanotherthing();

一切看起来很正常,但是仔细想想。这个宏会展开成:

if(temp)
    if(i) dosomething();
else
    doanotherthing();

这时的else不是与第一个if语句匹配,而是错误的与第二个if语句进行了匹配,编译通过了,但是运行的结果一定是错误的。

为了避免这个错误,我们使用do{….}while(0) 把它包裹起来,成为一个独立的语法单元,从而不会与上下文发生混淆。同时因为绝大多数的编译器都能够识别do{…}while(0) 这种无用的循环并进行优化,所以使用这种方法也不会导致程序的性能降低。

此外,这是为了含多条语句的宏的通用性。因为默认规则是宏定义最后是不能加分号的,分号是在引用的时候加上的。

在MFC的afx.h文件里面, 你会发现很多宏定义都是用了do...while(0)或do...while(false)。

为了看起来更清晰,这里用一个简单点的宏来演示:
#define SAFE_DELETE(p) do{ delete p; p = NULL } while(0)
假设这里去掉do...while(0),
#define SAFE_DELETE(p)   delete p; p = NULL;
那么以下代码:
if(NULL != p) SAFE_DELETE(p)
else   ...do sth...
就有两个问题,
1) 因为if分支后有两个语句,else分支没有对应的if,编译失败。
2) 假设没有else, SAFE_DELETE中的第二个语句无论if测试是否通过,会永远执行。
你可能发现,为了避免这两个问题,我不一定要用这个令人费解的do...while,  我直接用{}括起来就可以了
#define SAFE_DELETE(p)   { delete p; p = NULL;}
的确,这样的话上面的问题是不存在了,但是我想对于C++程序员来讲,在每个语句后面加分号是一种约定俗成的习惯,这样的话,以下代码:
if(NULL != p)  SAFE_DELETE(p);
else   ...do sth...
由于if后面的大括号后面加了一个分号,导致其else分支就无法通过编译了(原因同上),所以采用do...while(0)是做好的选择了。

如果使用名家的方法

#define SAFE_FREE(p)   do {free(p);p=NULL;}  while(0)

那么

if(NULL!=p)

        SAFE_FREE(p);

else

         do something

展开为

if(NULL!=p)

do

      { free(p);p=NULL;}

while(0);

else

        do something

好了 这样就一切太平了。


网易 2013

http://blog.youkuaiyun.com/dqjyong/article/details/8058209

  出于保密的原因,具体的题目就不说了,主要是我们不是为了做题目而分析题目,而是要将考点弄懂浓透。下面列举出本次试卷中的考点:

           1.给定入栈顺序,求出可能的出栈顺序。(点评:老得掉渣得题目了,只要小心点都没有问题)

           2.给定一个表达式,说出其后缀表示形式。例如给定X=A+B*(C-D)/E,求出其后缀表达式。

           3.四叉树中包含地空指针数量有多少?假设每个节电含有四个指向其孩子的指针,那么给定n个节点,其4n个指针有多少指向空?(比较简单的题目,n个节点使用了的指针有n-1,所以最后的答案位4n-(n-1)=3n+1)

           4.那个排序算法是非稳定的?选择,冒泡、希尔,堆排序,快速等  (也是比较基础的题目)

           5.内存管理:段页式管理,地址映射表方面的知识。(操作系统方面的知识也不能掉以轻心呀)

           6.进程与线程的区别:系统调度是对进程还是线程,线程与进程共享的内存空间、公共地址空间等;

           7.tcp/ip协议的实际使用过程中的问题:例如单方面断开后,另一端出于哪种状态,还有

           8.数据库方面的知识: 

                          主键和索引的基本定义及其性质,例如主键在表中是否唯一,索引的速度以及对表的改变的影响;

          9.数据库:数据库的不可重复访问异常,四种事务隔离级别中哪些可以避免该类异常?

各隔离级别对各种异常的控制能力 


LU丢失更新 DR脏读 NRR非重复读 SLU二类丢失更新 PR幻像读
未提交读 RU Y Y Y Y Y
提交读 RC N N Y Y Y
可重复读 RR N N N N Y
串行读 S N N N N Y

          10.读程序能力的考察:

                    例如:

[cpp]  view plain copy
  1. template<class T> class array   
  2. {  
  3.      public:  
  4.          array(T a):_size(a),_data(a){};  
  5.          int getDataSize(){return _data.size();}  
  6.          T getSize(){return _size;};  
  7.      private :  
  8.          vector<T> _data;  
  9.          T  _size;  
  10.                                  
  11. }  
  12. int main()  
  13. {  
  14.        array<int> *arr = new array<int> array(3);  
  15.         cout<<arr->getSize()<<endl;  
  16.         cout<<arr->getDataSize()<<endl;  
  17. }  

           输出为什么?分析一下原因?

还有一个程序:

[cpp]  view plain copy
  1. int main()  
  2. {  
  3.      char a[] = "abcd";  
  4.      char *p = a;  
  5.      int b =strlen(a);  
  6.      *a=p[b];  
  7.      ++p;  
  8.      cout<<p<<endl;  
  9.      cout<<a<<endl;  
  10.      return 0;  
  11. }  


         11.斐波那锲数列:常考点

         12.写一个程序来确定系统是大端模式还是小端模式;

         13.编程实现采用位操作来实现整数的加法操作。

         14. 图的矩阵表示法,图的深度优先遍历,算法思路及其实现。

         15.CAS(compare and swap)操作实现:(具体原理可以参考)

         16.fork函数的用法。具体题目为:

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <sys/types.h>  
  3. #include <unistd.h>  
  4.    
  5. int main(void)  
  6. {  
  7.    int i;  
  8.    for(i=0; i<2; i++){  
  9.       fork();  
  10.       printf("-");  
  11.       fflush(stdout);  
  12.    }  
  13.    
  14.    return 0;  
  15. }  

          问题是输出为几个‘-’?具体分析可以参见: 一个fork的面试题

         17.spin lock原理:

              先来一些代码吧!

              void initlock(volatile int* lock_status)

              {

                      *lock_status = 0;                       

             }

              void lock(volatile int* lock_status)

              {

                      while(test_and_set(lock_status = =1);                       

             }

             void unlock(volatile int* lock_status)

             {

                     *lock_status = 0;

             }

             问题:volatile的作用?lock函数优化(针对在多cpu上提高cpu cache)?上面的缺陷(内存模式上的)?

         18.给定一个巨大的文件,如何从中选出k行,随处输出k行到文件中。要求每一行出现的概率都相等。设计算法、说明思路,算法复杂度。

         19.win32中WM_Quit的作用是什么?

         20.比较mutex和临街区之间的区别,并说明其使用场景。

         21.多线程编程,如何安全退出线程。

         还有网易数据挖掘方面的题目,这次数据挖掘的题目比较新奇,都是简答题。如下:

        1,简述你对数据与处理的认识;
        2,简述你对中文分词的理解,说明主要难点和常用算法;
        3,常见的分类算法有哪些;
        4,简述K-MEANS算法;
        5,设计一个智能的商品推荐系统;
        6,简述你对观点挖掘的认识

  网易游戏笔试的人太少,因此可提供的笔试题目都不全,只是听说特别的难。还有好多是数学方面的智力题。例如:

1、英雄升级,从0级升到1级,概率100%。

从1级升到2级,有1/3的可能成功;1/3的可能停留原级;1/3的可能下降到0级;
从2级升到3级,有1/9的可能成功;4/9的可能停留原级;4/9的可能下降到1级。
每次升级要花费一个宝石,不管成功还是停留还是降级。
求英雄从0级升到3级平均花费的宝石数目。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值