这是一篇叙述自己在360公司参加笔试和面试的过程,可能面试的职位并不是你所学的方向,但是如果你能从中学到些什么或者吸取我的教训,那么作者就非常知足了。本着"学习别人是怎么失败的,活着出来的人才能成功"的目标,我从三个方面进行叙述:
第一部分:360公司笔试题
第二部分:面试过程
第三部分:注意事项及心得体会
同时,真心感谢360公司,我非常向往的一个公司。也非常感谢给我面试的那位大哥,让我真的学到了很多东西。所有题目版权归360所有,如果有不适的地方请告知我删除或修改。总之我认为:有的时候了解别人失败的案例比你总看别人成功的例子对你的帮助更大。看了下面我的本科毕设,你就会知道为什么我这么推崇这个公司了。
下载地址: http://download.csdn.net/detail/eastmount/8591789
面试时间: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
<?php class a{ function a($x=1) { $this->myvar=$x; } } class b{ var $myvar; function b($x=2) { $this->myvar=$x; parent::a(); } } $obj=new b; echo $obj->myvar;?>
<?php header("content-type:image/jpeg"); $img=imagecreatefromjpeg("images/scce.jpg").imagejpeg($img); imagedestroy($img);?>
<?php class my_class{ var $value; } $a=new my_class; $a->my_value=5; $b=$a; $b->my_value=10; echo $a->my_value;?>
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
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输出:每个数分成若干个素数乘积形式,从小到大输出。素因子之间用"*"形式连接。
例:
输入:
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客户端断开连接,
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); coutdatarchild); }}
非递归遍历
根据中序遍历的顺序,对于任一结点,优先访问其左孩子,而左孩子结点又可以看做一根结点,然后继续访问其左孩子结点,直到遇到左孩子结点为空的结点才进行访问,然后按相同的规则访问其右子树。因此其处理过程如下:
对于任一结点P,
1)若其左孩子不为空,则将P入栈并将P的左孩子置为当前的P,然后对当前结点P再进行相同的处理;
2)若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将当前的P置为栈顶结点的右孩子;
3)直到P为NULL并且栈为空则遍历结束
void inOrder2(BinTree *root) //非递归中序遍历{ stack<bintree> s; BinTree *p=root; while(p!=NULL||!s.empty()) { while(p!=NULL) { s.push(p); p=p->lchild; } if(!s.empty()) { p=s.top(); coutdatarchild; } } } </bintree>
2.然后又问我有什么问题,我说想自己实现个小的搜索引擎系统;他给我分析了硬件设备、分词、索引、倒排序、Rank、推荐系统等等知识。
3.最后让我出去等了大概15分钟左右,好像他们那天也比较忙,最后还是方向不太对口被拒了。但我自己已经非常知足了,一方面从他那学到了很多,另一方面也深深认识到了自己的不足,当初随便报了个PHP方向居然能面试,我也不知道报了这个方向。
在最后总结之间,说点题外话。在回学校之前,因为360公司就在798艺术工厂的旁边,我去到那里逛了3个多小时。写下这样一段话:
“今天早上来360面试,估计已跪,但仍不虚此行。会不会编程我不知道,但去了它旁边的798,发现自己还是有艺术细菌的。
好喜欢这种什么也不想,什么也不做,就静静地坐在角落,看着川流不息的人行的感觉。是那样的踏实惬意,那样的无忧无虑~
因为不喜旅游,否则再忙也要出去看看这大千世界。但有时候又觉得做个井底之蛙也没有什么不好的,至少还可以每天看月亮。”
??Eastmount
版权声明:本文为博主原创文章,未经博主允许不得转载。