猿辅导(实习800/天)面试算法题详解

不是标题党:猿辅导的实习薪资确实开到了800一天,度娘截图如下:

博主第一次听说猿辅导这家公司也是因为逆天的实习薪资,也正是因为这个原因博主才投递了简历,并且在拿到满意的offer之后依旧去参加了面试。仅仅因为好奇,想体验实习800一天的公司面试。

博主8月中上旬参加了猿辅导的在线笔试,猿辅导的笔试时间很紧张,四十多分钟好像:选择题和两道编程题。编程题不能跳出考试页面,相当于记事本撕代码,时间很紧。其中一道笔试题是:用指定字符在屏幕上输出“Y”形状,“Y”的各部分的长度都是通过输入给定。感觉与算法无关,更多属于细节和代码功底的考察。

现在回过头来看,猿辅导的面试注重点和今日头条很相似:java基础、源码和算法,这两个公司的面试基本都没怎么问项目。面试呢,猿辅导一共只有两轮技术面,一面主要是:java语言的一些基本语法特性、JDK源码和手撕算法。今天和大家分享的是博主在猿辅导一面期间遇到的两道算法题,两道算法题都是原题。

是不是原题其实不是很重要,原题不是你轻视面试的原因。重要的是:你问问自己能不能在十分钟内完成A4纸手撕代码?能不能保证代码的正确率?能不能清晰的向面试官描述你的代码思路(否则会觉得你表达能力有问题)?

如果不能,即使是原题又如何呢?没有任何意义。如果能,那么恭喜你,offer在向你招手。博主当时在十分钟内给出了没有bug的代码,所以也顺利通过面试了。言归正传,这两道算法题如下:


1

第一道是剑指offer上的原题,基本没有算法,更多是代码细节处理和代码功底的考察。第一道题目是顺时针打印矩阵,具体要求如下:

假设有一个如下的4*4矩阵:

你只需要顺时针打印这个矩阵,上面输入对应的输出顺序是:

【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 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上的原题,如果你还不知道该刷哪些算法题,该如何准备秋招,强烈建议看这篇文章:这篇文章详细介绍了整个秋招准备过程,学习方法。学习资料、简历、找面经方法等等,基本涵盖了秋招的所有相关事情。

**这两道算法题你花了多长时间手撕代码呢?**欢迎评论区留言分享讨论~


扫描下方二维码,及时获取更多互联网求职面经javapython爬虫大数据等技术,和海量资料分享:公众号后台回复“csdn”即可免费领取【csdn】和【百度文库】下载服务;公众号后台回复“资料”:即可领取5T精品学习资料java面试考点java面经总结,以及几十个java、大数据项目资料很全,你想找的几乎都有
扫码关注,及时获取更多精彩内容。(博主今日头条大数据工程师)

推荐阅读
我的【奇葩经历】分享

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值