面试时间:2015年9月16日
面试岗位:PHP服务端开发工程师
职位要求:精通PHP/Python语言语法、掌握MySQL,基本了解Redis和MongoDB等各种DB、掌握HTML/CSS等。
题目难度:较难,选择题考得比较广,编程题一道极为简单一道比较复杂。
PS:因为当时题目都是一边做一边在草稿纸上抄的,可能有遗漏的地方,请海涵~
(一) 单选题:
1.MySQL存储过程的优点:
某选项可以多次调用、修改,网络负载降低
2.找出/etc/my.conf文件属于哪个包(package),执行:
A.rpm -qf /etc/my.conf B.rpm -q /etc/my.conf
C.rpm -q | grep /etc/my.conf D.rpm -requires etc/my.conf
题解: 该题考察linux,答案是A。其中-f Query package owning FILE,赛马网:
-ivh:安装显示安装进度--install--verbose--hash
-Uvh:升级软件包--Update;
-qpl:列出RPM软件包内的文件信息[Query Package list];
-qpi:列出RPM软件包的描述信息[Query Package install package(s)];
-qf:查找指定文件属于哪个RPM软件包[Query File];
-Va:校验所有的RPM软件包,查找丢失的文件[View Lost];
-e:删除包
3.下面代码的运行结果:
A.1 B.警告,没定义a::$myvar
C.2 D.一个错误,没定义a::$myvar
myvar=$x; } } class b{ var $myvar; function b($x=2) { $this->myvar=$x; parent::a(); } } $obj=new b; echo $obj->myvar;?>题解:答案A. 参考
my_value=5; $b=$a; $b->my_value=10; echo $a->my_value;?>题解:通过 http://www.mcqyy.com/RunCode/php/ 运行结果为C.10
15.HTML5中,input元素type属性默认值为:
A.search B.hidden C.text D.form
题解:默认应该是text
16.下列代码的输出结果是:
A.24 B.17 C.72 D.36
d=lambda p:p*2t=lambda p:p*3x=2x=d(x)x=t(x)x=d(x)print x题解:感觉lambda表达式替换 2*2=4 4*3=12 12*2=24,应该输出A。Right?
34.下列关于继承错误的是:
A.只能公有继承,不能私有继承
B.派生类可以访问基类protect成员
C.一个基类可以继承多个派生类,一个派生类可继承多个基类
D.基类中至少有一个虚函数可构成多态
35.下列代码的输出值为多少:
int main(int argc, char **argv)
{
int a[4] = {1, 2, 3, 4};
int *ptr = (int *)(&a + 1);
printf("%d", *(ptr - 1));
}
A.3 B.1 C.2 D.4
题解:答案D。参考赛马网:
考察对于数组和指针的认识,指针加一的能力由类型决定。int*ptr=(int*)(&a+1); &a 和a 都指的是数组首元素的地址。不同的是a就是a+0 ,*(a+0)就是a[0],而&a+1相当于a[]数组类型的指针加1,此时指针加到数组的末尾。ptr接受后,由于Ptr的类型是int* 因此ptr-1即回退4字节。即指到最后一个元素。
36.下列可作为对象继承之间的转换的是:
(二) 编程题:
1.计算器的新功能
可视化程序设计一个新功能的计算器,输入一个数时,能将这个数分解为一个或多个素因子乘积的形式,并按素因子的大小排列显示出来,0-9这十个数字表示如下:每个数字占5*3大小的字符区域。
输入:多组测试数n(n<=1,000,000)
输出:每个数分成若干个素数乘积形式,从小到大输出。素因子之间用"*"形式连接。
例:
输入:
10
2
输出:
- - | | - * - | | - - - | - | -首先需要计算素数组成,然后难点是怎样将数字一次性从上往下显示出来。
面试时间:2015年10月9日
面试部门:服务器端开发
面试地点:360大厦
面试时长:100多分钟
PS:过程中可能存在一些遗漏的地方,但是还是非常感谢那个面试的哥哥,今天都还觉得给人很舒服的感觉。同时因为间隔时间太长,最近也太忙,不准备采用对话方式进行,而是分几个步骤进行简单叙述。
第一部分 自我介绍
1.首先简单问候面试官并递上自己的简历,然后做个自我介绍;
2.面试官通过我的简历,让我介绍自己最拿得出手的项目,我介绍的是知识图谱相关的项目,包括:传统搜索引擎的工作原理、知识图谱概念(举例姚明身高、梁启超关系查询)、实体消歧与实体对齐、采用的VSM向量模型及聚类算法;
3.面试官问我该阶段主要熟悉什么语言?我说现在做得最多的是Python,以前是C/C++,当然Java、C#、PHP都做过,毕竟语言都有通性,但是想精通还是难。
4.他说PHP比较简单,他们是做底层服务器方向的,今天的面试主要是问Unix相关知识;我也赞同这个观点,因为PHP可以通过一些开源框架实现,同时也问了些自己做的WAMP网站。
第二部分 Unix为主
1.面试官首先问我是否做过Unix相关的东西?我说自己就简单做过Linux下的Python爬虫、脚本等。
2.然后问了Unix下的网络编程会不会?我简单介绍了Python的网络编程TCP\UDP的过程,主要的三次过程如下,同时Socket其他语言过程基本类似。
服务器:
ss = socket() # 创建服务器套接字
ss.bind() # 地址绑定到套接字上
ss.listen() # 监听连接
inf_loop: # 服务器无限循环
cs = ss.accept() # 接受客户端连接 阻塞式:程序连接之前处于挂起状态
comm_loop: # 通信循环
cs.recv()/cs.send() # 对话 接受与发送数据
cs.close() # 关闭客户端套接字
ss.close() # 关闭服务器套接字 (可选)
客户端:
cs = socket() # 创建客户端套接字
cs.connect() # 尝试连接服务器
comm_loop: # 通讯循环
cs.send()/cs.recv() # 对话 发送接受数据
cs.close() # 关闭客户端套接字
3.然后他又问如果客户端出现异常,服务器怎样捕获这个异常呢?我当时想了下,提出了服务器可以设置一个时间点(心跳),当某段时间没有接受到该客户端的报文,则表示断开连接或异常错误。他又问我能不能把这段recv()函数写出来。我说不太会。
PS:回来后想了想,当时是不是在考察recv()函数的返回值: >0获得报文长度, =0客户端断开连接,<0连接发生异常错误。但确实自己也不会Unix下的网络编程。
4.面试官又问了些Unix下的fork相关的知识,我说没有接触过。还有些英文不知道是什么,自己英语太差了~
第三部分 算法和数据结构
1.面试官说:“你数据结构和算法应该很熟悉了吧!”我说:“还行,但是也忘记很多了。”自己确实很多基础知识都忘了很多,担心回答不上来。
2.面试官给我一张纸,有两段很长的代码(C语言),让我寻找两代码的区别。
这两段代码的主要区别就是参数一个是int,一个是double,当然前面还定义了些结构,代码里面的内容基本类似,相当于一个int型排序,一个double型排序。
他问我平时肯定会遇到这种情况,写两个函数代码过于冗余,怎样提炼成实现两种不同的类型排序,而且类型可以是float、结构体等等。
我说这有点类似于C++的模板啊!如果是C++就简单了,但是C语言主要是怎样判断这个类型呢?
PS:后来回来想了想,感觉类似于qsort快速排序的那种写法,通过const void *a实现,不知道是不是。但有同学怀疑是不是考察##的连接用法。
int型快排
int cmp1(const void *a, const void *b)
{
return *(int*)a - *(int*)b;
}
qsort(num, len, sizeof(int), cmp1);
double型快排
int cmp(const void *a, const void *b)
{
return *(double*)a > *(double*)b ? 1 : -1;
}
qsort(num, sum, sizeof(double), cmp);
char型快排
int cmp(const void *a, const void *b)
{
return *(char*)a - *(char*)b;
}
qsort(str, sum, sizeof(char)*10, cmp);
3.上面代码没有写出来,那么你就做个最简单的吧!二叉树中序遍历非递归实现。
他又问我以前是怎么做的?我说通常都是三句话递归,这个题主要是考察通过栈模拟二叉树遍历递归的过程,然后写代码中。我失误了,栈写成队列了,然后队列是先进先出,又通过两个队列(一个输入队列、一个输出队列)模拟了一个栈实现了非递归遍历。
中序遍历:左孩子-根节点-右孩子,总体代码如下。参考
递归代码
void inOrder1(BinTree *root) //递归中序遍历{ if(root!=NULL) { inOrder1(root->lchild); cout<data<<" "; inOrder1(root->rchild); }}
非递归遍历
根据中序遍历的顺序,对于任一结点,优先访问其左孩子,而左孩子结点又可以看做一根结点,然后继续访问其左孩子结点,直到遇到左孩子结点为空的结点才进行访问,然后按相同的规则访问其右子树。因此其处理过程如下:
对于任一结点P,
1)若其左孩子不为空,则将P入栈并将P的左孩子置为当前的P,然后对当前结点P再进行相同的处理;
2)若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将当前的P置为栈顶结点的右孩子;
3)直到P为NULL并且栈为空则遍历结束
void inOrder2(BinTree *root) //非递归中序遍历{ stack如下图所示:s; BinTree *p=root; while(p!=NULL||!s.empty()) { while(p!=NULL) { s.push(p); p=p->lchild; } if(!s.empty()) { p=s.top(); cout< data<<" "; s.pop(); p=p->rchild; } } }
2.然后又问我有什么问题,我说想自己实现个小的搜索引擎系统;他给我分析了硬件设备、分词、索引、倒排序、Rank、推荐系统等等知识。
3.最后让我出去等了大概15分钟左右,好像他们那天也比较忙,最后还是方向不太对口被拒了。但我自己已经非常知足了,一方面从他那学到了很多,另一方面也深深认识到了自己的不足,当初随便报了个PHP方向居然能面试,我也不知道报了这个方向。
在最后总结之间,说点题外话。在回学校之前,因为360公司就在798艺术工厂的旁边,我去到那里逛了3个多小时。写下这样一段话:
“今天早上来360面试,估计已跪,但仍不虚此行。会不会编程我不知道,但去了它旁边的798,发现自己还是有艺术细菌的。
好喜欢这种什么也不想,什么也不做,就静静地坐在角落,看着川流不息的人行的感觉。是那样的踏实惬意,那样的无忧无虑~
因为不喜旅游,否则再忙也要出去看看这大千世界。但有时候又觉得做个井底之蛙也没有什么不好的,至少还可以每天看月亮。”
??Eastmount
版权声明:本文为博主原创文章,未经博主允许不得转载。