赞
踩
本文转自我的个人网站:http://cuijiahua.com/
最近一直在参加各种面试,感觉自己面试表现很弱鸡,虽然已经有了点offer,但跟那些offer收割机比起来,差得太远。本篇文章记录了自己在面试过程中被问到的各种问题以及一些经验之谈。对于后续碰到的一些面试题,我会在个人网站持续更新持续更新。:点击查看
我选择岗位的标准是,找各个公司最适合我的实习岗位,有就投,没有就pass,因此我投递的岗位有些多样,主要投递的岗位:算法工程师、机器学习/深度学习工程师、数据挖掘工程师。
参加过的面试形式有:电话面、视频面、现场面。
对了,找面试期间,如果你的来电标有房产中介之类标识,也要接起来,不要直接挂断,因为没准这就是你面试官的副业(尴尬脸)。
参加面试各种不顺,深感自己的弱项在于数据结构掌握不行,剑指offer刷了一遍,怎奈脑子不够用,总是忘记,还需继续努力才是。
刚开始面试的时候,遇到了各种问题,也办了一些傻事。此处总结下,说下自己的感受:
刚开始参加面试的时候,很不自信。远程电话面试的时候,面对面试官的一个问题,我的第一反应是这个问题在哪看过,网上是怎么说的,甚至是在哪能找到答案。当时的我忽略了思考这个问题本身,而去想从何处能找到所谓的正确答案,自己的这一问题是准备不充分、不自信、紧张共同造成的结果。其实,如果认真的思考问题本身,答案并不难想到,而我往往是撂下电话,自己认真思考一下,然后悔恨不已:哇,刚才怎么没有想到!所以一句话:面对面试官的问题,一定要自己认真思考问题本身,自信一些,说出自己的想法,如果碰到耐心的面试官,他会一步一步引导你的。
刚开始我是“佛系”面试,一切随缘,真的一点不准备,也不知道自己应该看啥,然后面试了还蒙逼,明明有些不自信,还这么浪,可想而知,面试结果也很惨,二连跪,三连跪,跪得我都快站不起来了。当然,如果是真大牛,“佛系”面试也可以,怎奈我是一个渣硕,准备还是需要好好做的,因此决定痛改前非,重新做人。经过一段时间的准备,终于有些思路了,我认为需要着重准备以下几点:自我介绍、数据结构、简历项目、岗位需求。
有些公司电话说不定什么时候就打进来了,可能投递简历半个月了,你都忘记了。本以为是直接约个面试时间,结果上来直接面试。当然此时,可以说下自己现在不方便,可不可以另约时间。但是心里总会有疑虑:哇,这样到时候他会不会忘了?人到时候满了,自己进不去了?诸如此类的想法。其实,大多时候是没有问题的,不必有这些想法。不过,也不排除罕见的个别情况。所以,为了完全避免这些忧虑,时刻做好面试准备,保持电话时刻畅通是很有必要的。
内推很重要,如果没有内推,那么需要走简历筛选流程,就是HR从简历池把你的简历捞出来,如果没有捞出来,也就是没有相中你的简历,很可能你连个面试机会都没有,直接把你bass了。但是如果有内推,就会好很多。而且内推可以走提前批,大厂都有这些流程,意思就是不用等后面的统一笔试,直接面试。从哪找内推呢?
这一点我感觉也很重要,别上来就投BAT大厂的岗位,先试试其他公司,试试水。不过话又说回来,其实一些初创公司反而面试可能会更难,因为BAT这些大厂出题都是有迹可循,而一些初创公司说不定考你什么题,并且可能岗位要求比大厂还高。
值得注意的一点是,如果对于部门不了解,一定要好好了解一番,不要急着投递简历,咨询咨询别人,选择部门也是一门学问。
同时,比如一些笔试,如果没有信心,可以等一等,等第一波人做完了,咨询一下,至少什么类型的题你是能知道的。
曾经以为有个好的博客,牛的Github项目,就能有一些加分。现在发现,这个就要看面试官怎么看了,面试官感觉好,就有用。如果面试官感觉没用,那就作用不大。
个人感觉,这些东西只能算作一块好看一点的敲门砖。如果把没有这些的简历比作一个没用使用美颜和滤镜的摄像机拍下的砖头,那么有这些东西的简历就是开了美颜和滤镜的磨了皮的砖头。好看了一点,但是面试的时候,还是要看你的本质,需要好好准备内功才是。
尽管用处不是很多,我依然很喜欢做这些工作。因为我一直感觉自己脑子不够用,需要靠这些笔记回顾自己所学。别人看过的东西,等到用到的时候可以第一时间想起来;但是我有时候真的想不起来,但是我可以想起我在哪写过,我可以第一时间找到这篇自己写的文章,并且迅速回顾,然后用起来。所以,天赋不同,注定我要靠这种方式去弥补自己的不足。
除此之外,我感觉另一个好处就是,会有一些人主动联系你,帮你内推吧。当然,后续的面试情况还是要看你自己的。
感觉面试也很看运气,与其说是运气,不如说是面试技巧。感觉这个挺玄学的,不过它确实存在,你跟面试官很match,问的题目刚好是自己都会的,那么恭喜,这轮面试你就轻松过去了。不能否认运气的存在,更不能全靠运气,自身实力过硬,一切OK。
我遇到的问题,总共可分为六类:计算机基础、数据结构、机器学习相关、深度学习相关、项目相关、业务场景。
项目相关是根据个人简历问的,每个人的项目经历都不同,只需要根据事情阐述即可,此文不做记录,本文主要记录另外五类问题。
对于我找的方向来说,一般都会问一些linux基础,比如常用linux指令,这个如果平时经常用linux的话,问题不大。如果没有这方面基础的,就需要提前学一学了。还有就是会问一下关于你熟悉的计算机语言的基础知识,比如我说我更熟悉python,那么面试官可能就会问一些关于python基础的问题。
总结下我曾被问到的相关问题:
1、进程和线程的区别?
答:进程拥有一个完整的虚拟地址空间,不依赖于线程而独立存在;反之,线程是进程的一部分,没有自己的地址空间,与进程内的其他线程一起共享分配给该进程的所有资源。
比如:开个QQ,开了一个进程;开了迅雷,开了一个进程。在QQ的这个进程里,传输文字开一个线程、传输语音开了一个线程、弹出对话框又开了一个线程。所以运行某个软件,相当于开了一个进程。在这个软件运行的过程里(在这个进程里),多个工作支撑的完成QQ的运行,那么这“多个工作”分别有一个线程。所以一个进程管着多个线程。通俗的讲:“进程是爹妈,管着众多的线程儿子”。
参考自:https://www.zhihu.com/question/25532384
2、为什么说python的线程是伪线程?
答:在python的原始解释器CPython中存在着GIL(Global Interpreter Lock,全局解释器锁),因此在解释执行python代码时,会产生互斥锁来限制线程对共享资源的访问,直到解释器遇到I/O操作或者操作次数达到一定数目时才会释放GIL。
所以,虽然CPython的线程库直接封装了系统的原生线程,但CPython整体作为一个进程,同一时间只会有一个线程在跑,其他线程则处于等待状态。这就造成了即使在多核CPU中,多线程也只是做着分时切换而已。
参考自:https://www.zhihu.com/question/23474039
3、python的append和extend有什么区别?
答:extend()接受一个列表参数,把参数列表的元素添加到列表的尾部,append()接受一个对象参数,把对象添加到列表的尾部。
例如:
a = [1,2]
b = [1,2,3]
a.append(b)
print(a)
输出结果为:
[1, 2, [1, 2, 3]]
而:
a = [1,2]
b = [1,2,3]
a.extend(b)
print(a)
输出结果为:
[1, 2, 1, 2, 3]
4、linux下创建定时任务使用什么指令?
答:可以使用crontab命令。
个人感觉数据结构最重要,面试过一些公司,五花八门什么题都有,但是唯一统一,都考的就是数据结构基础了。但是考法不同,区别在于有的让说思路,有的让在线写代码。
私以为,复习的方法应该是:审题->思考->表达->码字。
首先,审题很重要无需废话,拿到题目,我们需要认真思考一番。然后就需要组织语言,把自己所想表达清楚。别小看这一个步骤,组织语言表达清楚很重要。一些公司都是先让说思路,再让写代码的,甚至是只说思路。所以,在复习的时候,把每道题的思路想清楚,说明白很重要。最后,我们再将自己的想法写成代码。
其实,这部分的数据结构基础题,只要《剑指Offer系列刷题笔记汇总》这些题目都掌握好,就足以应付,不会出太难的题目难为人,都是常规题。
下面对一些常见题型进行汇总,这些也是我面试时,真实被问到的题以及相关扩展题。
链表:
1、找出单链表的倒数第K个元素(仅允许遍历一遍链表)
答:使用指针追赶的方法,定义一个fast指针和一个slow指针,fast指针先走K步,然后fast和slow同时继续走。当fast指针走到链表尾部时,slow指向的位置就是倒数第K个元素。注意:要考虑链表长度应该大于K。参考:剑指Offer(十四):链表中倒数第k个结点
2、找出单链表的中间元素(仅允许遍历一遍链表)
答:使用指针追赶的方法,定义一个fast指针和一个slow指针,两个指针同时走,fast指针每次走两步,slow指针每次走一步。当fast指针到链表尾部时,slow指针指向的就是链表的中间元素。
3、判断单链表是否有环?
答:使用指针追赶的方法,定义一个fast指针和一个slow指针,两个指针同时走,fast指针每次走两步,slow指针每次走一步。如果有环,则两者会相遇;如果没有环,fast指针会遇到NULL退出。
4、已知单链表有环,如何知道环的长度?
答:使用指针追赶的方法,定义一个fast指针和一个slow指针,两个指针同时走,fast指针每次走两步,slow指针每次走一步,找到碰撞点。然后使用slow指针,从该碰撞点开始遍历,绕着走一起圈,再次回到该点,所走过的结点数就是环的长度。
5、如何找到环的入口结点?
答:先使用题4的方法,计算出环的长度。然后重新从头结点开始遍历,定义定义一个fast指针和一个slow指针,fast指针先走l(环的长度)步,然后两个指针以相同的速度在链表上向前移动,直到它们再次相遇,那么这个相遇点即为环的入口结点。参考:剑指Offer(五十五):链表中环的入口结点
6、判断两个无环单链表是否相交?
答:一旦两个链表相交,那么两个链表从相交节点开始到尾节点一定都是相同的节点。所以,如果他们相交的话,那么他们最后的一个节点一定是相同的,因此分别遍历到两个链表的尾部,然后判断他们是否相同。
7、如何知道两个单链表(可能有环)是否相交?
答:根据两个链表是否有环来分别处理,若相交这个环属于两个链表共有
(1)如果两个链表都没有环,如题6所示方法。
(2)一个有环,一个没环,肯定不相交。
(3)两个都有环。在A链表上,使用指针追赶的方法,找到两个指针碰撞点,之后判断碰撞点是否在B链表上。如果在,则相交。
8、寻找两个相交链表的第一个公共结点。
答:我们也可以先让把长的链表的头砍掉,让两个链表长度相同,这样,同时遍历也能找到公共结点。此时,时间复杂度O(m+n),空间复杂度为O(MAX(m,n))。参考:剑指Offer(三十六):两个链表的第一个公共结点
9、反转链表。
答:我们使用三个指针,分别指向当前遍历到的结点、它的前一个结点以及后一个结点。在遍历的时候,交换当前结点的尾结点和前一个结点的。参考:剑指Offer(十五):反转链表指
数组:
1、给定一个数组(非递减排序),同时给定一个目标数字,找出这个数字在该数组中第一次出现的位置,如果不存在,返回-1。例如[1,3,5,5,5,5,8,9,13,15],输入5,返回2,输入8,返回6,输入18,返回-1。
答:使用二分查找法即可。
# -*-coding:utf-8 -*-
def BinarySearch(input_list, end, value):
if end == 0 or value < input_list[0] or value > input_list[-1]:
return -1
left = 0
right = end - 1
while left <= right:
middle = left + (right - left) // 2
if input_list[middle] >= value:
right = middle - 1
else:
left = middle + 1
return left if left < end else -1
if __name__ == '__main__':
input_list = [1,3,5,5,5,5,8,9,13,15]
target = 5
print(BinarySearch(input_list, len(input_list), target))
运行结果如下图所示:
2、给定一个数组,里面有很多数字(乱序),找出其中最大的4个数字。
答:最简单的办法就是先排序再找出最大的四数,这种方法时间复杂度过高。一个更好的方法是使用堆排序,即维护一个存储最大的4个数的最大堆。
解析:这的思想和代码可以参考《剑指Offer(二十九):最小的K个数》,这里仅仅做了一个变形。
3、给定一个整数的数组nums,返回相加为target的两个数字的索引值。假设每次输入都只有一个答案,并且不会使用同一个元素两次。
答:如果这个数组是已经排序的,可以使用头指针和为指针。如果是已经排序的,那么我们可以定义一个头指针left,一个为指针right。left指针指向元素值+right指针指向元素值的和为sum,用sum和target比较。如果sum大于target,说明和大了,那么right右指针左移一位,然后重新判断。反之,如果sum 小于target,说明和小了,那么left左指针右移以为,然后会从新判断。直到找到sum=target的情况。如果没有排序,可以使用使用哈希表,也就是散列表。
解析:如果没有排序,这道题就是Leetcode中的一道题。代码可以参考《Two Sum》。
4、给定一个字符串,找到最长无重复子字符串。
答:定义两个变量longest和left,longest用于存储最长子字符串的长度,left存储无重复子串左边的起始位置。然后创建一个哈希表,遍历整个字符串,如果字符串没有在哈希表中出现,说明没有遇到过该字符,则此时计算最长无重复子串,当哈希表中的值小于left,说明left位置更新了,需要重新计算最长无重复子串。每次在哈希表中将当前字符串对应的赋值加1。
解析:Leetcode中的一道题。代码可以参考《Longest Substring Without Repeating Characters》。
其他:
1、不使用现成的开根号库函数,如何实现开平方根的操作?
答:可以使用二分查找法或者牛顿法。
# -*-coding:utf-8 -*-
def sqrt_binary_search(target):
left = 0
right = target
mid = (left + right) / 2
while abs(mid*mid-target) > 0.000001:
if mid*mid == target:
return mid
elif mid*mid > target:
right = mid
else:
left = mid
mid = (left + right) / 2
return mid
def sqrt_newton(target):
k = target
while abs(k*k-target) > 0.000001:
k = 0.5*(k+target/k)
return k
if __name__ == '__main__':
print("二分查找法:",sqrt_binary_search(64))
print("牛顿法:",sqrt_newton(64))
运行结果如下图所示:
1、什么是归一化,归一化的作用是什么?
答:归一化是将数据变为(0,1)之间的小数,主要是为了数据处理方便,把数据映射到0~1范围之内处理,处理起来可以更加便捷快速。归一化的作用是把有量纲表达式变为无量纲表达式,归一化是一种简化计算的方式,即将有量纲的表达式,经过变化,化为无量纲的表达式,成为纯量。同时,提高迭代求解的收敛速度,提高迭代求解的精度。
相应扩展:
深度学习中的归一化应该怎么理解?
答:神经网络学习过程的本质是为了学习数据分布,一旦训练数据与测试数据的分布不同,那么网络的泛化能力也大大降低;另一方面,一旦每批训练数据的分布各不相同,那么网络就要在每次迭代都去学习适应不同的分布,这样会大大降低网络的训练速度,这也正是为什么我们需要对数据进行归一化处理的原因。对于深度网络的训练是一个复杂的过程,只要网络的前面几层发生微小的改变,那么后面几层就会被累积放大下去。一旦网络某一层的输入数据的分布发生改变,那么这一层网络就需要去适应学习这个新的数据分布,所以如果训练过程中,训练数据的分布一直在发生变化,那么将会影响网络的训练速度。因此,我们一般会对输入数据进行”白化”除理,使得它的均值是0,方差是1。
2、标准化是什么?
答:数据的标准化是将数据按比例缩放,使之落入一个小的特定区间。由于信用指标体系的各个指标度量单位是不同的,为了能够将指标参与评价计算,需要对指标进行规范化处理,通过函数变化将其数值映射到某个数值区间。
相应扩展:
常见的数据归一化方法有哪些?
答:min-max标准化、z-score标准化等。
对于数据标准化/归一化的详细内容,可以参见:http://blog.csdn.net/pipisorry/article/details/52247379
3、你最熟悉的机器学习算法是什么?可以讲解下SVM原理吗?
答:省略若干字。
解析:这部分内容可以参考我的文章《机器学习实战教程(八):支持向量机原理篇之手撕线性SVM》,我当时面试的时候是先说的线性可分的情况,然后再引入核函数。
4、在推导公式的时候,为要向量化,这是什么意思?
答:其实就是将多组数据,放到一个矩阵里,进行矩阵运算。因为如果是一条一条遍历计算参数,需要用到for循环,这样很浪费时间。python的第三方库提供了很好的矩阵计算支持,我们完全可以把多组数据放到一个矩阵里,这样可以实现多组数据同时计算。这个向量化推导,就是根据一条数据计算公式推导出矩阵运算公式,这样可以方便我们写代码。
5、在逻辑回归中,我们使用的是sigmoid函数,知道sigmoid函数吧?
答:知道。
继续问:那么tanh函数和它有什么区别呢?
答:它们的值域不同,sigmoid函数将输出映射到0~1的范围内,而tanh函数将输出映射到-1~1的范围内。同时,它们过零点的值也不同,sigmoid函数的过零点的值为0.5,tanh函数过零点的值为0。当我们更偏向于当激活函数的输入是0时,输出也是0的函数时候,就需要使用tanh函数,而非sigmoid函数。
目标检测算法相关:
1、简述下YOLO算法原理?
答:Yolo算法采用一个单独的CNN模型实现end-to-end的目标检测,模型参考自GoogleNet,YOLO的CNN网络将输入的图片分割成SxS的网络,然后每个单元格负责去检测那些中心点落在该格子内的目标。每个单元格会预测B个边界框(bounding box)以及边界框的置信度(confidence score)。所谓置信度其实包含两个方面,一是这个边界框含有目标的可能性大小,二是这个边界框的准确度,边界框的准确度可以用预测框与实际框(ground truth)的IOU(intersection over union,交并比)来表征。边界框的大小与位置可以用4个值来表征:(x,y,w,h),其中(x,y)是边界框的中心坐标,而(w,h)是边界框的宽与高。还有一点要注意,中心坐标的预测值(x,y)是相对于每个单元格左上角坐标点的偏移值,并且单位是相对于单元格大小的,而(w,h)预测值是相对于整个图片的宽与高的比例。这样,每个边界框的预测值实际上包含5个元素:(x,y,w,h,c),其中前4个表征边界框的大小与位置,而最后一个值是置信度。每个单元格需要预测 (B*5+C) 个值。如果将输入图片划分为 S*S 网格,那么最终预测值为 S*S*(B*5+C) 大小的张量。对于PASCAL VOC数据,其共有20个类别,如果使用 S=7,B=2 ,那么最终的预测结果就是 7*7*30大小的张量。
解析:不用慌,只要自己思路清晰,说的连贯,不间断卡壳就行,其实如果面试官不了解这些,他也是听不懂的,但是最好不要瞎说,因为他也会查的,并且可能会抓住其中一点,深入细问,如果问的正好是你瞎编的内容,你就无法自圆其说了。
2、相对于YOLO,YOLO v2有哪些改进?
3、深度学习方法与传统机器学习方法的区别是什么?
答:机器学习包括深度学习,深度学习是使用卷积层学习特征,而非像机器学习那样需要人为提取特征,深度学习可以自行学习到更深层次的特征。机器学习方法的各个公式有数学理论推导支持,深度学习方法就像一个黑匣子,缺少数学理论支持。
这种题目也是常出题目,会给定你一个场景来提问。
1、如果给了你很多数据,这些数据已经标注好,即已经做好分类,现在让你训练出一个模型,用于区分新来的数据属于哪一类,你需要怎么做呢?可以说下详细的流程吗?
答:首先这是一个分类问题,首先应该想到的是可以尝试使用常用的分类算法,例如朴素贝叶斯、决策树或者SVM。拿到数据之后,做的第一件事就是特征工程。然后将数据分类两部分,一部分用于训练,另一部分用于测试,即分为训练集和测试集,不混用。其实,使用什么分类算法倒是其次,重要在于选好特征,对于给定的特征,需要做一些过滤,比如一些干扰数据,如果对于结果影响很大,可以尝试舍弃这些数据。除此之外,看看是否需要对数据进行归一化处理,将数据无量纲化。然后对已经处理好的特征,送入分类算法中,让其学习。最后,可以通过查看测试集的预测准确度,对一些算法必要参数进行优化调试。
解析:我当时差不多就是这么回答的,我感觉只要说的,让面试官认为你做过相关工作即可。
2、如果给你1亿个数据,让你找出其中第1000大的数据,你会怎么做?我们先不考虑多进程和多线程,也不考虑数据库,如何在算法方面给出思路呢?
答:可以使用堆排序,创建一个存储1000个数据的小根堆。先将1亿个数据的前1000个数据放入这个小根堆中,然后继续遍历,对于新插入的数据,需要与小根堆的最小值进行比较,如果待插入的数据比这个最小值还小,那么不插入,如果比这个最小值大,那么就插入该数,并重新调整小根堆,随后继续使用此方法遍历整个数据。遍历一次数据后,就得到了前1000大的数据,然后输出小根堆的最小值,即根值,即可得到第1000大的数据。
解析:这道题当时能想到的就是用堆实现了,其他更好的方法欢迎探讨。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。