您的位置:首页 > 职场人生

各大IT公司面试题

2013-10-27 00:16 351 查看

百度2道面试题:

【一、有一个桶,里面有白球,黑球各100个,人们必须按照以下的规则把球取出来:】

1.每次从桶里面拿出来两个球.

2.如果是两个同色的球,就再放入一个黑球.

3.如果是两个异色的球,就再放入一个白球.

问,最后桶里面只剩下一个黑球的概率是多少?

http://blog.csdn.net/linraise/article/details/13093759

思路1.

如果是两个白球,则放入一个黑球,(黑球多1个,白球少2个)

如果是两个黑球,则放入一个黑球,(黑球少1个,白球不变)

如果是一黑一白,则放入一个白球,(黑球少1个,白球不变)

由上面可以看出,每一次操作,球总会少1个,那么199次之后,球只剩下一个,所以剩下一个黑球的概率要么是1,要么是0.从上面可以看出,白球要么一次少2个,要么少0个.

所以最后不可能只剩1个白球,所以剩下一个黑球的概率是1.

思路2.

如果同色,则为0(黑球),如果异色,则为1(白球).是不是很像异或的性质?我们可以将黑球当成0,白球当成1.那么,

我们只需要关注所有的球最后的异或结果即可.

【二、算法题:给你一个自然数N,求[6,N]之内的所有素数中,两两之和为偶数的那些偶数.】

思路:这个题目有必要解释一下,举个例子,[6,13]之内的素数有7,11,13两两之和是偶数的有7+11,7+13,11+13,那么我们输出

18,20,24,这就是结果要求.(上面为什么所有的组合都是偶数?其实这是哥德巴赫猜想)

哥德巴赫猜想 : 任一大于2的偶数,都可表示成两个素数之和.

退一步想,我们要求[6,N]之内的所有素数中,两两之和为偶数的那些偶数,

意思是那些偶数只要在素数之和可表示的范围内,则它们都是满足条件的.(因为根据哥德巴赫猜想,偶数都能表示为两个质数之和)

我们只需要找到区间内最小的偶数和最大的偶数,然后输出它们中间的所有偶数即可.

代码:

#include <stdio.h>
#define N 100
int isPrime(int n)//判断是否是素数
{
if((n<2) || (n & 1)==0)
return 0;
//3往后的偶数绝对不是素数,可以越过,如果当前处理到i,则只需要处理i*i往后的即可
//因为i*1,i*2......i*(i-1)在1,2,.....(i-1)的时候被处理过了
for(int i=3; i*i<=n; i=i+2)
if( n%i == 0)
return 0;
return 1;
}

int main()
{
int n = N-1;
while(n < N)//找比N小的最大素数
{
if(isPrime(n))
break;
else
n--;
}
//[6,N]区间内最小的质数是7,最大的质数是n,那么
for(int i=14; i<=n*2;i+=2)
printf("%d\t", i);
return 0;
}

华为2014校园招聘机试

一、题目描述(60分):

通过键盘输入一串小写字母(a~z)组成的字符串。请编写一个字符串过滤程序,若字符串中出现多个相同的字符,将非首次出现的字符过滤掉。

比如字符串“abacacde”过滤结果为“abcde”。

要求实现函数:

void stringFilter(const char *pInputStr, long lInputLen, char *pOutputStr);

【输入】 pInputStr:  输入字符串

            lInputLen:  输入字符串长度         

【输出】 pOutputStr: 输出字符串,空间已经开辟好,与输入字符串等长; 

【注意】只需要完成该函数功能算法,中间不需要有任何IO的输入输出

示例 

输入:“deefd”        输出:“def”

输入:“afafafaf”     输出:“af”

输入:“pppppppp”     输出:“p”

main函数已经隐藏,这里保留给用户的测试入口,在这里测试你的实现函数,可以调用printf打印输出

当前你可以使用其他方法测试,只要保证最终程序能正确执行即可,该函数实现可以任意修改,但是不要改变函数原型。一定要保证编译运行不受影响。

#include<stdio.h>
#include<string.h>
#include <memory.h>

void stringFilter(const char *pInputStr, long lInputLen, char *pOutputStr)
{
bool isExisted[26];
memset(isExisted,0,sizeof(isExisted));
int i,j;
for( i=0 , j=0 ; i<lInputLen ; ++i )
{
if ( !isExisted[pInputStr[i]-'a'] )
{
isExisted[pInputStr[i]-'a']=1;
pOutputStr[j++]=pInputStr[i];
}
}
pOutputStr[j]='\0';
}

int main()
{
char* p1="aaabbaaccddss",p2[100];
stringFilter(p1,strlen(p1),p2);
printf("%s\n",p2);
return 0;
}
二、题目描述(40分):

通过键盘输入一串小写字母(a~z)组成的字符串。请编写一个字符串压缩程序,将字符串中连续出席的重复字母进行压缩,并输出压缩后的字符串。

压缩规则:

1、仅压缩连续重复出现的字符。比如字符串"abcbc"由于无连续重复字符,压缩后的字符串还是"abcbc"。

2、压缩字段的格式为"字符重复的次数+字符"。例如:字符串"xxxyyyyyyz"压缩后就成为"3x6yz"。

要求实现函数: 

void stringZip(const char *pInputStr, long lInputLen, char *pOutputStr);

【输入】 pInputStr:  输入字符串

            lInputLen:  输入字符串长度

【输出】 pOutputStr: 输出字符串,空间已经开辟好,与输入字符串等长;

【注意】只需要完成该函数功能算法,中间不需要有任何IO的输入输出

示例 

输入:“cccddecc”   输出:“3c2de2c”

输入:“adef”     输出:“adef”

输入:“pppppppp” 输出:“8p”

http://blog.csdn.net/linraise/article/details/12246339

void stringZip(const char *pInputStr, long lInputLen, char *pOutputStr)
{
if( pInputStr==NULL || lInputLen < 1 || pOutputStr==NULL)
return ;
int i,j=0,count=1;
for(i=0;i<lInputLen;++i)
{
if( pInputStr[i] == pInputStr[i+1])
++count;
else
{
if(count == 1)
pOutputStr[j++] = pInputStr[i];
else
{
sprintf(pOutputStr+j,"%d%c",count,pInputStr[i]);
j = strlen(pOutputStr);
}
count=1;
}
}
pOutputStr[j]='\0';
}


三、题目描述(50分): 

通过键盘输入100以内正整数的加、减运算式,请编写一个程序输出运算结果字符串。

输入字符串的格式为:“操作数1 运算符 操作数2”,“操作数”与“运算符”之间以一个空格隔开。

补充说明:

1、操作数为正整数,不需要考虑计算结果溢出的情况。

2、若输入算式格式错误,输出结果为“0”。

要求实现函数: 

void arithmetic(const char *pInputStr, long lInputLen, char *pOutputStr);

【输入】 pInputStr:  输入字符串

            lInputLen:  输入字符串长度         

【输出】 pOutputStr: 输出字符串,空间已经开辟好,与输入字符串等长; 

【注意】只需要完成该函数功能算法,中间不需要有任何IO的输入输出

示例 

输入:“4 + 7”  输出:“11”

输入:“4 - 7”  输出:“-3”

输入:“9 ++ 7”  输出:“0” 注:格式错误
#include<stdio.h>
#include<string.h>

void arithmetic(const char *input, long len, char *output)
{
int i,beg=0,end=0,isFirstSpace=1,isLegalChar=1;

for(i=0;i<len;++i)
{
if( input[i] == ' ')
{
if(isFirstSpace)
beg=i,isFirstSpace=0 ;//控制这里只记录第一个' '
else
end=i;
}
else
{
//合法的字符
if(input[i] =='+' || input[i] == '-' || (input[i]>='0' && input[i] <='9'))
;
else
{
isLegalChar=0;
break;
}
}
}
int num1=0,num2=0;
if(end - beg == 2 && beg > 0 && end < len  && isLegalChar && (input[beg+1]=='+' || input[beg+1]=='-'))
{
for(i=0;i<beg;++i)
num1 = num1*10+(input[i]-'0');
for(i=end+1;i<len;++i)
num2 = num2*10+(input[i]-'0');
if(input[beg+1] == '+')
sprintf(output,"%d",num1+num2);
else
sprintf(output,"%d",num1-num2);
}
else
{
output[0]='0';
output[1]='\0';
return ;
}
}
int main()
{
char input[]="1 - 2",output[100];
arithmetic(input,strlen(input),output);
printf("%s",output);
return 0;
}

请编写memcpy

已知memcpy的函数为: void* memcpy(void *dest , const void* src , size_t count)其中dest是目的指针,src是源指针。不调用c++/c的memcpy库函数,请编写memcpy。

要编写memcpy有陷阱,陷阱是要注得是否复制到了重复的内存.要防止内存污染.

void* memcpy(void *dst, const void *src, size_t count)
{
assert( (dst != NULL) && (src != NULL) );

unsigned char *pdst = (unsigned char *)dst;
const unsigned char *psrc = (const unsigned char *)src;

assert(!(psrc<=pdst && pdst<psrc+count));
assert(!(pdst<=psrc && psrc<pdst+count));

while(count--)
{
*pdst = *psrc;
pdst++;
psrc++;
}
return dst;
}

迅雷2014校招笔试编程题:

已知集合A和B的元素分别用不含头结点的单链表存储,函数difference()用于求解集合A与B的差集,并将结果保存在集合A的单链表中。例如,若集合A={5,10,20,15,25,30},集合B={5,15,35,25},完成计算后A={10,20,30}。
链表结点的结构类型定义如下:请完成函数void difference(node** LA , node* LB)

struct node
{
int elem;
node* next;
};

void difference(node** LA , node* LB)
{
node *pa , *pb , *pre , *q;
pre = NULL;
pa=*LA;
//1
while(pa)
{
pb = LB;
while(pb && pb->elem != pa->elem) //2
pb = pb->next;
if(pb)                   //3
{
if(!pre)
*LA = pa->next     ;     //4
else
pre->next= pa->next;     //5
q = pa;
pa = pa->next;
free(q);
}
else
{
pre=pa;             //6
pa = pa->next;
}
}
}

 京东/小米:谈谈你对面向对象编程的认识

面向对象四个基本点:抽象,多态(核心概念),继承,封装,
抽象:把一类事物共有的属性和行为提取出来,形成一个物理模型(模版)(概念)
封装:就是将类的属性封装起来,类内部的实现对类外部是封闭不可见的,只向外部提供接口。如设置属性或方法的访问权限(private、protected、public、默认)。

好处:

第一:重用;
第二:不必关心具体的实现;
第三:可以增强模块的独立性;
第四,具有安全性!

继承:让子类可以重用和扩展父类的代码.

好处:
把共性函数代码放入到父类中,把特性函数代码放入到子类中,使代码可以重用.
多态:一个对象变量可以指向多种实际类型的现象,通常是利用基类指针调用子类的函数,通过virtual函数实现.使得接口重用.
重载:相同的方法名,不同的实现机制(通过传入不同个数或类型的参数)。当程序运行时动态绑定。

重写:从父类继承而来的方法不能满足需要的情况下,可以将此方法的逻辑在子类中重新实现。

[华为面试题] 1分2分5分的硬币三种,组合成1角,共有多少种组合

[创新工厂笔试题] 有1分,2分,5分,10分四种硬币,每种硬币数量无限,给定n分钱,有多少中组合可以组成n分钱

思路:暂时不用想着如何一口将题目吃掉,我们一点一点地来分析。首先假定我们有m种类型的硬币(A1,A2,...Am),我们的目标是

求出用这m种类型的硬币组合sum分钱一共有多少种组合。如果第Ai种硬币取xi枚,则显然有下面的等式成立

sum = A1*x1+A2*x2+......+Am*xm ,其中 xi = 0,1,2..... 且 Ai*xi <=sum(即xi <=sum/Ai)   ...........................(1)

我们只需要求出(x1,x2...,xm)序列的组合数即为题目所求。

求组合数我们可以容易想到有两种思路:

其一:蛮力法,如果有m种类型的硬币,Ai的取值xi可能是{0,1,2....sum/Ai},则我们可以用m个嵌套循环去一个一个地判断(x1,x2...,xm)是否

满足要求,这种办法复杂性是O(sum/A1*sum/A2*sum/A1*....sum/Am)

其二:从上面的蛮力法可以看出:如果m太大,嵌套m层显然不合理,我们可以利用系统堆栈帮忙,即使用递归,对于当前的{0,1,2....sum/Ai}

中的每一种情况,都递用一次递归。这种虽然程序美观,但是效率和蛮力法是一致的。

还有一种办法,就是动态规划。

动态规划有三个最重要的步骤:

1.定义状态

2.找初始状态

3确定状态转移式

定义状态:我们可以定义前i种类型的硬币组合成s分钱,共有DP[i][s]种组合数。为什么这么定义呢?因为动态规划的办法就是大而化小,

从小往大推,各个击破。我们知道DP[i][0] = 1(初始状态,要组合0分钱,(x1,x2...,xi)只能有(0,0,....0)这一种组合方式)

从DP[i][0].......推到DP[m][sum]即为所求。

接下来找状态转移式:分解(1)式

考虑DP[i][s],可以由哪些状态转移得来,着眼于xi的取值

如果xi=0, 则有DP[i-1][s]种情况

如果xi=1,则有 DP[i-1][s-Ai]种情况

如果xi=2,则有 DP[i-1][s-Ai*2]种情况

...

如果xi=i,则有DP[i-1][s-Ai*xi]种情况。

集中起来就是:





上面的状态转移式在时间上是O(n^2)(i=0,1,2....m , k = 0,1....s/Am),

空间也是O(n^2),在空间上还是可以进一步压缩的,前边的i都是++i,所以省去这一维,变成





参考代码:

#include<iostream>
using namespace std;

int A[10]={1,2,5};
int dp[30][30];
int m,sum;

void DP()
{
int i,j,k;
memset(dp,0,sizeof(dp));
for(i=0; i<=m; ++i)
dp[i][0] = 1;
for(i=1; i<=m; ++i)
{
for(j=1; j<=sum; ++j)//填满dp[m][sum]矩阵
{
dp[i][j] = 0;
for(k=0; k<=j/A[i-1]; ++k)
dp[i][j] += dp[i-1][j-A[i-1]*k];
}
}
cout << dp[m][sum] << endl;
}
int main()
{
m = 3,sum=10;
DP();
return 0;
}

另一种思路:
/**************************************************************************
第16题:华为面试2:1分2分5分的硬币,组成1角,共有多少种组合。
组成i分,有dp[i]种组合,
dp[0]=1
组成i分,可以选择1分,然后再选择组合i-1分,也可以选择2分,然后再选择组合i-2分,
也可以选择5分,然后再选择组合i-5分.这些是或关系,用加法
***************************************************************************/
#include <memory.h>
#include <stdio.h>

int w[3]={1,2,5},dp[101];
void DP()
{
memset(dp,0,sizeof(dp));
dp[0] = 1;
for(int i=0; i<3; i++)
{
for(int j=w[i]; j<=10; j++)
{
dp[j] += dp[j - w[i]];//确保每个dp[i]只加3次
}
}
}
// n:钱数,单位:"角",网上牛人解法,暂时还不明白
int f(int n)
{
return 5*n*n+4*n+1;
}
int main()
{
DP();
printf("%d\n",dp[10]);
printf("%d\n",f(1));
return 0;
}

其余见:http://bbs.csdn.net/topics/370186303

美团网2014校招研发笔试哈尔滨站

1、链表翻转。给出一个链表和一个数k,比如链表1→2→3→4→5→6,k=2,则翻转后2→1→4→3→6→5,若k=3,翻转后3→2→1→6→5→4,若k=4,翻转后4→3→2→1→5→6,用程序实现

对数组左旋转,<编程珠玑>已经提供了好几种思路:http://blog.csdn.net/linraise/article/details/12237185

现在需在将数组变成链表,要如何改动呢?可以参考<编程珠玑>的解法5,只需要将数组的reserve子程序改成链式即可.

node* reserve(node* head,node* tail)//反转[head,tail)之间的链表
{
if(head == tail || head->next==tail)
return head;

node* newHead=reserve(head->next,tail);
head->next->next=head;
head->next=tail;
return newHead;
}
node* reserve(node* head,int k)
{
if(head==NULL)
return head;
node *cur=head,*newHead=head;//这里一定要newHead=head,不能置为NULL,否则会断节
int i;
for(i=0;i<k && cur!=NULL ;++i)//找到分割点
cur=cur->next;
if(i==k)
{
newHead=reserve(head,cur);//先处理前边的
head->next=reserve(cur,k);//递归处理后边的
}
return newHead;
}

创新工场2014校招笔试题

1.堆排序.
http://blog.csdn.net/linraise/article/details/9107747

2.求一个正整数的开方,要求不能用库函数qsrt,结果的精度在0.001即可.
http://blog.csdn.net/linraise/article/details/13170521

3.给定一个短阵,int matrixA[m]
,每行每列都是增序的,实现一个算法去寻找
杨氏矩阵:
#include<stdio.h>

bool SearchInArray(int* A,int rows,int cols,int expectedNum)
{
int row=0;
int col=cols-1;
while(row < rows && col >=0 )
{
if(A[row*cols + col] == expectedNum)//A[row][col]
return true;
else if(A[row*cols + col] < expectedNum)//A[row][col]
++row;
else
--col;
}
return false;
}
int main()
{
int A[][4]={
{1,2,8,9},
{2,4,9,12},
{4,7,10,13},
{6,8,11,15}};

printf("%d\n",SearchInArray((int*)A,4,4,8));
return 0;
}

阿里巴巴笔试题

29.(8分)在黑板上写下50个数字:1到50,在接下来的49轮操作中,每轮做如下动作:选取两个黑板上的数字a和b,擦去,在黑板上写上|a-b|,
请问最后一次动作之后剩下数字可能是什么?为什么?(不用写代码,不分析原因不得分)
思路:
这道题的出题风格很类似<桶中取黑白球>,分析类似上面的百度第一题.a,b可能是一奇一偶,一偶一偶,一奇一奇,一偶一奇四种情况,
如果是擦去两个同奇或者同偶的数,结果是|a-b|(偶数),如果是擦去一奇一偶,则|a-b|结果是奇数.这样就可以和异或对应起来.同为偶(0),异为(1).
50个数中有25个偶数(0),25个奇数(1).全部异或结果是1,所以,最后剩下的数字可能是1-50中的某一个奇数.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息