不是标题党:猿辅导的实习薪资确实开到了800一天,度娘截图如下:
博主第一次听说猿辅导这家公司也是因为逆天的实习薪资,也正是因为这个原因博主才投递了简历,并且在拿到满意的offer之后依旧去参加了面试。仅仅因为好奇,想体验实习800一天的公司面试。
博主8月中上旬参加了猿辅导的在线笔试,猿辅导的笔试时间很紧张,四十多分钟好像:选择题和两道编程题。编程题不能跳出考试页面,相当于记事本撕代码,时间很紧。其中一道笔试题是:用指定字符在屏幕上输出“Y”形状,“Y”的各部分的长度都是通过输入给定。感觉与算法无关,更多属于细节和代码功底的考察。
现在回过头来看,猿辅导的面试注重点和今日头条很相似:java基础、源码和算法,这两个公司的面试基本都没怎么问项目。面试呢,猿辅导一共只有两轮技术面,一面主要是:java语言的一些基本语法特性、JDK源码和手撕算法。今天和大家分享的是博主在猿辅导一面期间遇到的两道算法题,两道算法题都是原题。
是不是原题其实不是很重要,原题不是你轻视面试的原因。重要的是:你问问自己能不能在十分钟内完成A4纸手撕代码?能不能保证代码的正确率?能不能清晰的向面试官描述你的代码思路(否则会觉得你表达能力有问题)?
如果不能,即使是原题又如何呢?没有任何意义。如果能,那么恭喜你,offer在向你招手。博主当时在十分钟内给出了没有bug的代码,所以也顺利通过面试了。言归正传,这两道算法题如下:
1
第一道是剑指offer上的原题,基本没有算法,更多是代码细节处理和代码功底的考察。第一道题目是顺时针打印矩阵,具体要求如下:
假设有一个如下的44矩阵:*
你只需要顺时针打印这个矩阵,上面输入对应的输出顺序是:
【1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10】
你可以认为函数的输入是一个二维数组(表示矩阵),返回值是矩阵的打印顺序集合。
题目应该不难,基本没有算法。看到完题目的小伙伴,停下来动手试试,即使你以前做过这道题,可以试试看:十分钟内能否A4纸手撕出代码,并且保证正确率?切记,仅仅在脑海里想远远不够,动手写写看。在动手写代码前一定要整理好思路,没有打通思路动手也是白搭,大概率是浪费时间,代码只是思路的一种体现,思路很重要,编程语言倒是其次。
往下看之前先想想,我们需要些什么条件来实现顺时针打印。往下看之前建议停下来想想,解决这个问题你需要什么条件?只要可以满足所有你需要的条件:问题就迎刃而解了,代码也就呼之欲出了。
2
顺时针打印肯定得知道当前打印到哪一行和哪一列了;其次不能出现越界和重复打印。
第一点很好实现,定义两个变量row和col指向当前打印的行和列即可;第二点,顺时针打印其实是一圈一圈的打印,打印过程中的任何一次顺时针打印圈都可以用四个变量唯一确定:当前圈的最一行和最后一行;当前圈的最左列和最右一列。越界问题其实也就是要限定row和col变量的取值范围。
下面用top表示当前打印圈的第一行、left表示当前圈最左列、bottom表示当前打印圈的最后一行、right表示当前打印圈的最右边一列。这四个变量中top和bottom是用来限定row的取值范围;left和right是用来限定col的取值范围。
到这里代码思路大致介绍完了,读者可以停下来,自己动手码一下代码,面试中很注重手撕代码的能力,仅仅有思路写不出实现代码也是不行,所以强烈建议拿出A4纸或者【没有提示功能的编辑器】动手撕一波代码。
3
具体而言,上面案例打印输出的第一圈输出应该是:
【1,2,3,4,8,12,16,15,14,13,9,5】
这个圈可以用
top=0;bottom=3;left=0;right=3
来唯一确定;
打印的第二圈的输出为:
【6,7,11,10】
这个圈可以用:
top=1;bottom=2;left=1;right=2
来唯一确定。
对打印边界的限定可以避免出现数据的重复处理,即之前已经打印输出过的数据再次被输出;也可以防止数组越界异常。当出现:top>bottom或者left>right则表明所有的数据都已经处理完了。java代码如下
public ArrayList<Integer> printMatrix
(int [][] matrix) {
if(matrix==null) return null;
//获取矩阵的行和列
int row = matrix.length;
int col = matrix[0].length;
//保存待返回的结果集
ArrayList<Integer> res
= new ArrayList(row*col);
int top=0,left=0;
int bottom=row-1,right=col-1;
while( left<=right
&& top<=bottom ){
//打印left->right, left<=right
for(int m=left;m<=right;m++){
res.add(matrix[top][m]);
}
//打印top->bottom top<=bottom
for(int m=top+1;m<=bottom;m++){
res.add(matrix[m][right]);
}
//打印right->left
//只剩一行时left->right和right->left
//打印的是同一行,所以没有重复必要处理
if( top!=bottom )
for(int m=right-1;m>=left;m--){
res.add(matrix[bottom][m]);
}
//打印bottom->top
//只剩一列时top->bottom和bottom->top
//打印的是同一行,所以没有重复必要处理
if(right != left)
for(int m=bottom-1;m>top;m--){
res.add(matrix[m][left]);
}
//为打印下一圈做准备
top++;
left++;
bottom--;
right--;
}
return res;
}
这里再次强调一点:不要刻意去强调原题之类的,也不要觉得是原题就眼高手低。你唯一应该关注的是【你能不能手撕出代码、正确率又是多少】,面试的时候碰到一个原题却写不出代码或者正确率达不到,这真的很扎心,到时一定恨不得给自己两巴掌。另外,刷题一定要总结!博主也会尽力为大家总结一些常见题型的解法,博主的每篇文章不会为了发文章而发文章,文章最后都会有解题方法总结。
4
总结:数组、矩阵类的题大多思路是:
-
使用边界指针,通过某种方式移动边界指针(每次移动一步或者二分法移动)
-
贪心暴力算法:通过递归的方式遍历所有可能的解法,选出满足条件的组合
-
动态规划:当前的状态要和之前的状态有关,以空间换时间
-
HashMap<元素值,数组索引>或HashSet去重特性,这两个数据结构用的很多
-
快慢指针法
数组要尽量利用有序、不重复之类的条件,任何有序字眼都要想想能不能用二分法,二分是log级别的复杂度,如果能用,基本就是最优解了。不能用二分然后试试上面其他几类方法。猿辅导一面的第二道算法题也是和数组有关。
5
第二道面试题,题目描描述很短,如下:
给你两个有序的数组,要求:找出这两个数组合并之后的中位数。要求:最小时间和空间复杂度。
这个题在线性时间复杂度O(n)很好解:维护两个指针找出第k大的数,这里的k就是:数组合并后的中位数位置。但是这不是最优解,你回答完O(n)的思路后,面试官肯定会问你也没有更优的解法。
一旦面试官询问更优解法,其实是“此地无银三百两”,大概率是有的,要不面试官问你就没有意义了,这更多是一种提示。回到上面总结部分,有序数组如果可以使用【二分法】,就能达到log级别的复杂度,大概率是最优解,所以思路肯定转到二分发上面去了。
这个题博主在面试百度的时候也曾遇到过,具体解法请看这篇文章。博主当时在五分钟内给出了代码实现,并使用上面那篇文章中介绍的图解方法向面试官介绍了完整的解题思路。这道题解完,面试官说了一句话:“今天的面试就到这里了,等待下面的二面通知。”如果这道题解得不那么好,怕是只能收到面试官的前半句话了。
面试题时的手撕算法大多是牛客网和LeetCode上的原题,如果你还不知道该刷哪些算法题,该如何准备秋招,强烈建议看这篇文章:这篇文章详细介绍了整个秋招准备过程,学习方法。学习资料、简历、找面经方法等等,基本涵盖了秋招的所有相关事情。
这两道算法题你花了多长时间手撕代码呢?欢迎评论区留言分享讨论~
扫描下方二维码,及时获取更多互联网求职面经、java、python、爬虫、大数据等技术,和海量资料分享:
公众号菜鸟名企梦
后台发送“csdn”即可免费领取【csdn】和【百度文库】下载服务;
公众号菜鸟名企梦
后台发送“资料”:即可领取5T精品学习资料、java面试考点和java面经总结,以及几十个java、大数据项目,资料很全,你想找的几乎都有
推荐阅读
我的【奇葩经历】分享
网友评论