头像

我要出去乱说

凯里学院 => 贵州大学




离线:11小时前


最近来访(390)
用户头像
aaa辰
用户头像
acwing_陌路
用户头像
初静
用户头像
ssuunn
用户头像
努力ing
用户头像
yyh蒟蒻
用户头像
cht
用户头像
星愿烦行
用户头像
琅琊
用户头像
喵喵酱
用户头像
谷歌生草姬
用户头像
拿不到offer不改名
用户头像
猪啊猪
用户头像
eyetofreedom
用户头像
也.
用户头像
INnoVation
用户头像
anji
用户头像
Sonicyouth
用户头像
若白
用户头像
蓬蒿人

新鲜事 原文

今天偶然看到一张图,虽然可能是玩笑,但看了心里很难受,都有画面感了,要是真遇到这种情况,到底该怎么办啊,哎
图片



职位:Android开发工程师(可接受java方向)

本来不太想接这个面试的,因为当时手里已经有百度后端研发和ThoughtWorks软开两个offer了,但约面的面试官语气很诚恳,实在不忍拒绝,就接了。

1、 数组中出现次数超过一半的数字

2、 环形链表 II

3、 螺旋矩阵

面试官话不多说,上来就甩给我三道题,要求半小时做完,结果我做了32分钟,第三题还没调试出来,担心时间不够,就先提交了,边界判定太烦,给我干懵了。

4、了解安卓开发吗?为什么选安卓开发?

因为我之前实习用QT写过桌面级的客户端,感觉客户端开发很有意思,但现在桌面级客户端开发越来越少了,所以想转到移动端。目前我对安卓开发不是很了解,但有兴趣去学。

5、堆与栈的区别?

  • 堆是由程序员分配并释放的,效率比栈要低,但可用空间比栈大,比如mallocnew就是在堆上申请内存空间,使用后若不释放会造成内存泄漏;
  • 栈是由编译器来自动分配释放的,效率高,但栈空间通常较小,比如定义一个局部变量,就是放在在栈空间中的,由于栈空间由编译器控制,所以不存在内存泄漏。

6、构造函数能否重载?

这里我傻了,我说不能重载,其实是可以重载的,最典型的就是带参数重载:

class Box {
public:
    Box();
    Box(int h, int w, int l):height(h), width(w), length(l){}   //构造函数的重载
private:
    int height, width, length;
};

7、如何理解抽象类?

类中含有纯虚函数即为抽象类。抽象类不能实例化,比如动物类下面可以有狮子、老虎、熊猫等等派生类,这些派生类是能够实例化的,但动物本身不能实例化,因为它是一个抽象的概念。

8、指针和引用的区别?

9、预编译过程做了哪些事情?

预编译主要是做了宏定义展开和引入头文件(应该还可以说一个条件编译)的工作。

10、说说归并排序?

11、TCP/IP的协议栈?

其实就是说OSI的七层模型,我从上往下说了一遍。

12、HTTP协议头部的TTL字段代表什么?

代表报文的最大跳数(最长生存时间),主要是为了防止报文段在网络中一直循环的进行传输所设置的,当达到最大跳数后该报文段会被自动丢弃。

13、git你熟悉到什么程度?

我说了常用的pulladdcommitpushmerge操作。

追问:知道cherry-pick吗?

不知道。感觉git真是博大精深,不是特别熟悉的话简历上还是慎写,不然一问就懵。

14、闲聊在学校和实习做了什么(12min)

15、目前还有其他offer吗?

手里现在还有个外企的offer,不过是做软件外包的(其实我觉得这家外企挺好的,但我故意说得不太行的样子,抬一手小米)。

追答:嗯对,外包公司确实你要慎重,因为加班严重,待遇也不是很好,毕竟做的不是自己的东西,巴拉巴拉说了一大堆。

16、能来实习吗?

不能,我现在正在实习,10月底实习完就返校了,不再实习了。

17、你对加班怎么看?

我对996深恶痛绝,这是资本家对我们的压榨,我恨加班(不能说的心里话)。
其实做这一行加班我觉得是挺正常的,自己有心理准备,实习的时候为了尽快完成自己的工作,我也常常加班。

反问:像我这种完全没有安卓开发经验的应届生能胜任这个职位吗?

面试官建议我有时间还是多学习一些相关的知识,话里话外能听出来他不太想招一个完全没有安卓开发经验的应届生。

总结

之前被字节的客户端开发给洗脑了,到处都是客户端0基础,mentor一对一,包教包会的内推广告,我还以为客户端都是低门槛呢,看来也不全是这样。第二天直接给了感谢信,效率挺高的。不出意外的话这可能是我秋招的最后一次面试了,现在已经完全不想刷题背八股文了。等着中秋后谈薪吧。




部门:美团金服

岗位:移动端开发工程师

面试前寒暄

晚上七点的面试,迟到了几分钟,我说我刚下班赶回来,迟到了不好意思啊。面试官说你们那么早就下班了啊,我们这边可没那么早下班哦。我苦笑说既然选择了这行,我是有心理准备的哈哈。聊了几分钟当前实习的内容和上一次实习的内容。

1、为什么选移动端呢?你自己是偏向后端还是移动端?

我最近也有听说很多关于客户端不好的传言,比如客三消什么的,但我自己没有那么悲观喇,难道三年后AppStroe里的应用就没有了吗,我觉得不可能,其实我对客户端的发展前景还是比较乐观的。并且我上次实习也是用QT写桌面级的客户端,觉得挺有意思,虽然还没接触过安卓和IOS,但也有兴趣去学。

这里我故意避开第二问不谈,因为确实是送命题,不知道怎么答才好。。

2、你还有投过其他公司的移动端吗?

投过,我还投了字节的移动端,但是字节笔试太难了,就没通过。面试官听完笑了笑。

3、看你简历写了十大排序,你说说这些排序的应用场景?

我掰着指头一个一个地说,结果只说出来六个,尴尬。还被追问什么是基数排序?什么是桶排序?我刚好忘了,只能说不知道。

现在已经把简历上精通十大排序这句话去掉了,谢谢面试官排雷。

4、HTTP头部结构是怎样的?HTTP1.0、1.1、2.0都有什么区别?

5、HTTP有什么缺点?

不安全,因为是明文传输,如果想要安全的话,就得加密。

追问:加密完就安全了吗?

仅仅加密还不够,HTTP安全要满足四个特性,除了加密以外还要保证数据传输的完整性(摘要算法),要有身份认证(CA证书)和不可否认(当时没答出来)。

6、你说一下TCP三次握手过程?

我感觉应该是前面没答好,所以来了个简单题给我打打气。

7、IP协议在OSI七层的哪一层?它的作用是什么?它是怎么把数据发送到目的地的?

8、I/O多路复用有什么用?

主要是为了解决服务器端并发的问题,如果没有多路复用的话,就只能通过多进程或多线程阻塞等待事件,效率较低。使用I/O多路复用相当于委托内核来检测就绪的事件,效率会高一些。

9、说一下git你常用的命令?

我简单说了一些基本操作:add,commit,push,pull等。

追问:如果我commit后,想要修改commit的内容,如何操作?如何撤销commit?git分为三个区域,是哪三个?git add 后会进入哪个区域?

直接给我干懵了,我赶紧说太久没用了,记不清了。

简历:熟练使用git

10、说说一个C++程序从编写到运行的过程?

预编译->编译->汇编->链接。

追问:说说编译的过程,具体一些。

我答不上来,面试官又问我看没看过《编译原理》这本书,我说没看过。好家伙都干到汇编去了。后来查了下百度,编译具体过程如下:

  • 词法分析阶段,该阶段会对构成源程序的字符串进行扫描和分解,识别出一个个的单词;
  • 语法分析阶段,该阶段用于分析句子的语法结构;
  • 语义分析与中间代码产生阶段;
  • 代码优化阶段;
  • 目标代码生成程序阶段。

11、算法题:判断一棵二叉树是否是搜索二叉树。

12、算法题:反转链表(从第k个节点后开始反转)。

两个算法题我写了25分钟,才把核心代码写出来。我这编码能力是越来越差了啊。。

总结

大厂就是大厂啊,客户端都问得那么难,感觉已经卷不动了,麻了。



新鲜事 原文

今天是值得庆祝的一天,我拿到了第一个offer哈哈!一家外企,955感觉还不错
图片



遍历子节点,递归求深度。

class Solution {
public:
    int maxDepth(Node* root) {
        if (root == nullptr) return 0;

        //子节点的最大深度
        int max_depth = 0;

        //遍历该节点的每个子节点
        for (int i = 0; i < root->children.size(); ++ i)
            max_depth = max(max_depth, maxDepth(root->children[i]));

        //返回子节点的最大深度+当前节点(表示为加1)
        return max_depth + 1;
    }
};



岗位:软开-北京

0、8.14 投递简历

1、8.20 收到测评

相当于笔试,90min,题量比较大,包括单选题多选题填空题以及三道算法题,不过不难。尤其是算法题,全都只是力扣简单难度,甚至还不到简单难度,暴力做法即可通关。全程不需要开摄像头,不需要手机开监控,不限制开始时间,你在半夜做也可以,但一定不能在中途跳出浏览器外。这个笔试可以说是秋招以来做过最畅快的笔试了,学到很多。

2、8.28 一面:结对编程

会提前三天发邮件约面,给你一个github链接,你去clone项目,熟悉代码,然后面试官在面试时会提需求让你实现,并测试。那几天我刚好在实习,很忙,直到面试前一天才配置好VS环境把项目跑起来,都没来得及细看,不太熟悉代码,直接硬着头皮上了,过程中犯了很多低级错误,编译器一直给我报语法错误,调试了老半天,可尴尬了。

我感觉这个环节最重要的是思路,其实最后提的需求我没实现,更谈不上测试,但是我思路对了,面试官给予我肯定。一个小时的面试,时间非常紧,因为zoom这个会议室待会儿还要有其他面试者使用,所以每个人只有不到一个小时的时间。

3、9.05 二面:文化面

ThoughtWorks的流程是很慢的,基本上每一个阶段都需要等一周。这次文化面邮件上写明了只有半小时,会考察英文,所以我准备了英文自我介绍,很短,就刚好一分钟的长度。

这次面试可能我答得太快,只用了18分钟,面试官就把问题问完了,果然让我用英文做自我介绍,还好准备了。文化面不会问技术内容,感觉主要考察你这个人合不合适。

最后反问阶段:

  • ThoughtWorks对新员工有一个怎样的培养体系?

答:每个新员工都会有为期一个月的ThoughtWorks University培训(我网上查了一下这个培训还挺有意思的),然后会给你配一个buddy来结对编程,然后还说了很多,我一下子没记住。

  • 工作会经常出差吗?

答:会,但也看你自己的意愿,出差包括国内和国外。

总结

文化面是最后一面,接下来就是等待结果了。ThoughtWorks的面试体验真的很棒,如果你备受互联网大厂八股文+算法的双重折磨,去体验一下TW的面试,会颠覆你的认知。能感觉到TW是倡导平等,尊重的公司,了解得越多对TW越感兴趣哈哈。因为要保密,所以不能透露具体问题。

9.07晚上收到offer




岗位:测试开发工程师
部门:美团优选

一面(42min)

1、说一下OSI七层模型,每层有什么协议?

  • 最上层是应用层,有HTTPHTTPSFTPSMTP这些协议;
  • 然后是会话层和表示层,这两层我不太了解;
  • 下面是传输层,有TCPUDP
  • 再下面是网络层,有IPICMP
  • 最底端是数据链路层和物理层,这两层我也不太了解,不知道有什么协议。

2、HTTPHTTPS有什么区别?

3、看你简历上有写熟悉gccgit,你说一下平时是怎么用它们的?

gcc可以用来编译C程序,最近我常用它来生成动态库和静态库,比如-share参数可以生成动态库,-L指定动态库目录,-l指定动态库文件名,-I指定头文件目录等;

追问1:静态库与动态库有什么区别?

静态库相当于把所需的目标文件都整合到一起,不需要外部依赖,但是体积较大,动态库可以只将需要的函数接口放进去,体积小,更灵活,但是会有外部依赖。

追问2:你有没有试过把编译好的程序放到其他机器上运行?能运行成功吗?

如果直接拷贝过去的话可能没法直接运行,需要配一些环境变量,比如动态库路径等。

git的话我一般是用git add .命令添加修改的文件,然后用git commit -m "commemt"提交,双引号里面写这次修改的内容,最后用git push origin推送到远端。

追问3:你一般是直接在主分支(master)上进行修改吗?

不是,一般是从主分支拉一个新分支,在新分支上修改代码,最后再合并到主分支。

追问4:如果协同开发,那么肯定会有分支冲突,你是怎么解决冲突的呢?

解决冲突这块不太熟,答得不好,最后我干脆直接说不会解决冲突。。

4、看你简历里写了挺多排序啊,十大排序哈哈,那你说下快排的原理?

经典八股文,我一顿狂背,原理+优化方法,结果说到一半被面试官打断施法了。

追问:快排与归并有什么区别?

  • 归并时间复杂度是稳定的O(logN)而快排是不稳定的,最好O(logN),最坏O(N*N)
  • 归并本身是稳定排序,快排不是。

5、你简历上说了解MySQL,那你写几个增删改查语句吧

我说增是用insert,改是用update,但我平时没怎么写过,都不会写,只会写查的语句,就是select的语句。

追问1:知道多表联查吗?

知道,用left join可以实现多表联查,相当于在多个表的并集里面做查询。

追问2:left joinright join有什么区别?

right join我听过,但是没用过,不知道有什么区别。

参考答案:

  • left join(左连接)表示以左表为主关联右表的数据,查询结果显示左表的数据,和右表中与左表有交集部分的数据;
  • right join(右连接)表示以右表为主关联左表的数据,查询结果显右左表的数据,和左表中与右表有交集部分的数据;
  • join(内连接)表示查两个表的交集部分。

6、进程与线程有什么区别?

7、用没用过管道?

用过,程序里面可以用管道pipe进行通信,命令行里的|也是管道。

追问1:用grep和find命令,找/root/目录下所有名字格式类似YYYY-MM-DD.log的文件中包含connection time out的日志。

我说我不会写正则表达式,面试官说可以不写,于是我解答如下:

find /root -name "YYYY-MM-DD.log" | grep "connection time out"

这里被面试官秀了,本来我敲的是对的,然后他质疑说find这个地方写得有问题,我赶紧说哦哦对对应该那样写,然后他又质疑我grep那个地方写得有问题并问我是否知道xargs这个命令,我赶紧说哦哦对对应该用这个命令。然后他说刚才两点他提的都是错的,我写的本来就是对的,为了考验我是否自信。最后他说出这句话他自己都笑了,我也蚌埠住了,直接笑场。

8、为什么想做测开?

我觉得大家在学的时候应该都是往后端开发这个方向去学的,我最开始也是这么想的,但上次实习的时候发现测开其实挺有意思的。那时候我们部门有个很厉害的测开工程师,我每次实现一个功能,自己测了一下觉得没问题了,结果人家一眼就能看出很多破绽。而且做开发的话可能就只对几个技术栈比较熟悉,但是做测开的话,知识面会更广,技术栈也可以下潜很深,如果同时能保持广度和深度的话就太厉害了,所以我也想做测开工程师,往这个方向去发展。

9、既然你对测开那么感兴趣,那你最近有没有主动去了解过测开的一些知识?

有,但我现在时间很有限没有办法系统地去学,只是知道一些简单的概念,比如黑盒测试白盒测试这些概念,我还知道现在很流行用python来写自动化测试框架,但我自己也还没有时间去学phthon

追问:黑盒测试与白盒测试有什么区别?

  • 黑盒就是不去看程序内部,而是只根据输入输出来判断功能是否健全,好处是简单、测试成本低,但是容易遗漏bug;
  • 白盒测试就是去看程序内部的实现,需要一些开发知识,成本较高,比如开发人员的自测就属于白盒测试。

面试官给我说不只是python可以写自动化测试框架,JavaC++也可以,美团自研的自动化测试框架就是用Java来写的,只不过现在python比较流行。

10、设计测试用例

题目:5层楼,包含地下一层,每层两个电梯厢,每个电梯厢有自己的按钮(外面),里面有许多按钮:-1,1,2,3,4,警报铃,开门、关门,请你设计测试用例。

  • 进电梯按指定的楼层是否能到达该楼层,按警报玲会不会响,开门关门是否正常;
  • 电梯里面应该有一套算法,比如你按下电梯,离你楼层较近的那台电梯会来接你;
  • 停电的时候电梯里的应急灯会不会亮,里面通信设备能不能呼救;
  • 承重方面,如果电梯人数超过上限会不会响警报;

追问:如果你第一天测,电梯是正常的,但第二天就出问题了,你会怎么办?

我觉得应该要增加测试的频度。

面试官补充:除了承重以外,还需要测一下电梯门的规格大小,比如你搬东西进去,能搬多大的东西,这也是需要测的一点。

11、问实习项目中遇到最大的困难是什么?

我说项目中要实现一个ssh功能,我觉得比较困难。

追问:你用过telnet吗?telnetssh有什么区别?

没用过telnet,不太清楚。

参考答案:telnet是明码传输,ssh是加密传输;telnet所用端口是23,ssh是22。

总结

美团测开感觉还是比较简单的,居然算法题都没写,惊了哈哈。现在面试已经比较从容了,不会的东西就直接说不会,感觉能和面试官谈笑风生,不再过分严肃和紧张。



新鲜事 原文

刚刚做了Thoughtworks的测评,相当于笔试吧,10个选择题,3个读代码段计算输出的填空题,三个算法题。选择题包括单选多选,感觉质量还是挺高的,不会有那种特别复杂的需要大量计算的题,都是比较有意思,需要一点小小思考的题。三个算法题说实话连力扣简单难度都谈不上,核心代码模式。对于做惯了力扣的同学可以直接秒杀,外企考察的东西果然与国内不同啊,感觉更偏重逻辑和推理,不像国内全是八股文和很难的算法题。90分钟的笔试做得很舒服,很畅快,体验确实好。而且外企不加班哈哈,感觉周末双休真的非常重要!我现在在天融信实习,已经两个周末加班了,周六周日都加班是真的离谱,哎,不说了,明天还要早起加班。。希望秋招能找到WLB的工作



岗位:后端开发
部门:技术与数据中心-数据与智能-智能优化部

1、问项目和实习项目

因为我两个项目都比较水,其实没啥可问的,但这次面试官深挖了近20分钟,第一次有人挖那么深,问得我都怀疑自己做没做过这个项目了。

其中问了我的聊天室项目是用的TCP还是UDP?

我答TCP,面试官反问:如果你有100个好友在线,但你只跟一个好友聊天,那么其他99个好友的连接都要一直保持吗?然后给我解释了像微信、QQ这类聊天软件都是基于UDP的。

2、了解C++新特性吗?说一下move的用法?说一下智能指针?

C++11的新特性这块我其实比较薄弱,因为没有动手写过,都只记得一些概念。但是现在面试问得实在是太多了,move右值引用、智能指针这些一定要背牢。我就把简单的概念给面试官说了一遍。

追问:unique_ptr能作为返回值吗?unique_ptr是怎么实现独有权的?

第一问我答不知道,第二问我也不知道,但我猜是把构造函数、拷贝构造函数和赋值运算符声明为私有了。面试官说答的方向是对的,unique_ptr其实是对拷贝构造和赋值运算符使用了delete关键字,禁用了。后来我查了下资料:unique_ptr没有拷贝构造,赋值运算符,但是有move构造,move赋值,unique_ptr对象可以被函数返回。

3、说说map和unordered_map的区别?

  • map底层是红黑树,增删查的时间复杂度为O(logN),其中键值是有序的;
  • unordered_map底层是哈希表,增删查的时间复杂度为O(1);

追问unordered_map是否线程安全?需不需要用锁?

这问的太细了,我直接说不知道,然后反问面试官:需要用锁吗?面试官说需要。

我后来查了下资料,根据C++标准:任何对STL集合的读取访问都是线程安全的。写入操作不是线程安全的。

4、编程题: 替换空格

面试官很照顾我,给了我一个剑指offer第五题原题:将字符串中的空格替换成%20,然而不争气的我又忘了最优解法怎么做了。。我上来就直接写了个最差解法,声明另一个字符串,遍历原字符串,遇到空格就在新字符串上累加%20,否则直接累加原字符串的字符。面试官说空间复杂度太高,我又想了老半天,没想出来,求面试官给点提示。面试官说我应该先计算替换后的字符串长度,再从后往前遍历,原地构造字符串,我突然明白了,编写代码如下:

#include <iostream>
#include <string>
using namespace std;

int main()
{
    string s;
    getline(cin, s);

    int old_length = s.length(), real_length = 0;
    for (int i = 0; i < s.length(); ++i)
    {
        if (s[i] == ' ') real_length += 3;
        else real_length += 1;
    }
    //注意resize后s的length值等于real_length,所以前面我要保存一个old_length
    s.resize(real_length);

    real_length -- ;
    for (int i = old_length - 1; i >= 0; -- i)
    {
        if (s[i] == ' ')
        {
            s[real_length -- ] = '0';
            s[real_length -- ] = '2';
            s[real_length -- ] = '%';
        }
        else s[real_length -- ] = s[i];
    }
    cout << s << endl;
    return 0;
}

resize我还真是第一次面试时用,期间面试官问了我resizereserve的区别,我说resize会改变lengthcapacity,而reserve只改变capacity不改变lengthsize,这题换思路重写+debug花了近18分钟

反问环节

  1. 您的部门主要是做哪方面的开发工作呢?

    面试官说跟深度学习相关,训练模型什么的,我大惊,难道是被算法岗捞了??

  2. 请问您的部门需要求职者掌握深度学习相关的知识吗?

    这个不需要,这些东西进来再学都可以,你看我都没问过你TF相关的东西吧,我们这边开发主要还是用C++,更看重基础。

总结

终于意识到了自己写这个聊天室项目是有多水。。京东面试官说你这不会是课程设计吧?百度二面面试官说你这项目随便一本讲网络编程的书应该都有(暗指没有必要做)。我又能说什么呢,我就说因为我是通信专业的,主要是抱着学习的心态,通过这个简单的项目了解一下网络编程的过程。

这次京东的面试官给我的实习项目挑了许多刺,关键是还给我解释清楚了,说如果是他的话他会怎么做等等,我直接记下来,下次再有面试官问我:“你觉得你在项目中遇到最大的困难是什么?哪些地方可以优化?”我就可以直接抄他的答案了哈哈。




岗位:C++/GO/PHP研发工程师
部门:搜索技术平台研发部

一面(86min)8-11

该面筋尽可能真实还原我面试时作答的内容和状态。

八股部分

1、 MySQL索引如何实现?

索引底层是用B+树实现的,B+树非叶子节点存储的都是索引,只有叶子节点才存储真正的数据,并且叶子节点用链表连接起来,主要是方便范围查找。

2、 B+树与红黑树有什么区别?为什么MySQL索引不用红黑树?

经典八股文,我竟一时想不起来,沉默了一会儿我说忘记了,面试官继续下一个问题。

3、 谈谈你对I/O多路复用的理解?selectepoll有什么区别?

项目中有用到I/O多路复用,所以问了。

如果不使用I/O多路复用的话,服务器端就只能通过多进程多线程实现并发(这里忘了说线程池优化,不然还能多扯一点的),调用accept函数阻塞等待客户端请求,效率较低。使用I/O多路复用的话就相当于把检测就绪文件描述符的工作交给了内核,提高了效率。select第一个参数是监听套接字描述符,中间三个参数分别是读事件、写时间和错误文件描述符集合,最后一个参数是超时时间,poll的参数就比较少,用了一个结构体把三种文件描述符集合包含进去了。selectLinuxWindows平台通用的,pollepollLinux独有的,而且select检测文件描述符个数有上限,是1024个,在内核中写死了,而pollepoll中没有限制。

第二问我脑子突然宕机,想不起来了,面试官提示说select需要遍历文件描述符集合,我突然记忆恢复,赶紧接着说对对,select每次需要遍历整个文件描述符集合,才能找出就绪的文件描述符,效率低,而epoll会直接返回已就绪的文件描述符集合(这里还可以说epoll是通过红黑树来管理待检测集合的,我也忘了说了),而且selectpoll都有在内核态与用户态的数据拷贝,而epoll使用了共享内存(mmap),省去了不必要的内存拷贝。

4、 实习项目中的解耦与优化具体是做了什么?

我是接手的一个QT项目,之前的开发人员把所有功能函数全都写在一个mainWindow文件中了,导致文件很臃肿,改起来很累,于是我把每个页面单独拆分成一个文件,函数根据功能分成字符串处理类、I/O类、按钮功能类等等,根据类拆分到不同的文件中,这样就是解耦了。

感觉答得也不是很好,实际上做的工作远没有达到我说的这种程度哈哈。

5、 聊天室项目最大的难点是?以及一些实现细节?

网上找的一个很简单的项目,总共只有六百行代码,基于命令行的项目。之前面试的时候面试官都不屑于问我项目相关的东西,没想到这次终于问了,结果因为太久没复习了,答得不是很好,项目具体用了哪些数据结构都记不清了。

6、 介绍快排原理?

  • 首先快排是不稳定排序,因为它是通过交换元素来实现的,接着说了快排实现原理,这里就不详细展开了,然后说了快排适用于完全乱序的序列,不适用与基本有序或基本逆序的序列,最后我主动说了优化方法;
  • 我之前看过侯捷老师的《STL源码剖析》,stl里面其实对快排做了一些优化,比如在选择哨兵的时候使用三数取中法,即取序列第一个元素、中间元素以及最后一个元素,再取这三个元素的中位数作为哨兵,这样可以避免取到边缘值而导致每次分割不均匀的情况;
  • 第二种优化方法,因为在递归分割序列时,序列的长度会越来越短,又因为短序列排序中插入排序效率最高,所以可以设置一个阈值,当序列长度分割到阈值时切换到插入排序,提高效率;
  • 第三种优化,当序列中存在大量相同元素,或者全是相同元素时,使用快排仍然会得到最低效率,这时可以采用聚集相等元素的方法,每次选择哨兵后,将与哨兵相同的元素放到序列中间,下次分割时中间这些值不参与分割;
  • 其实还有第四种优化方法,我当时忘记了,没说。第四种优化,当递归层数过深的时候改用堆排序,虽然第一个优化方法避免了取到边缘哨兵,但还是有可能取到较边缘的哨兵,最坏的情况会导致递归层数过深,从而降低快排效率,所以每次递归要判断递归层数,达到一定深度就改用堆排序,这是stl源码里实现的方法。之所以要用堆排序,我猜想可能是因为快排和归并都是基于递归的排序,此时递归深度已经太深,肯定不能再用了,而对于较长的序列使用插入排序效率也不是太高,所以选择了堆排序。
  • 最后的最后分析了快排的时间复杂度最好情况为O(NlogN),最坏为O(N^2),空间复杂度最好的情况为O(logN),因为递归时函数压栈需要空间,最坏情况为O(N),一个快排呱呱呱说十分钟感觉问题不大。

7、 介绍虚函数?

  • 虚函数是为了实现C++的多态性,运行时多态。在基类中声明一个虚函数,在其派生类中重写该函数,在程序运行时就可以根据指针所指对象的类型来调用对应的方法,而不是根据指针本身的类型来调用方法,这是虚函数的一个用法;

  • 还有一个用法是将类中的析构函数声明为虚函数,主要是为了应对这样一种情况,当基类指针指向派生类对象,删除这个指针时,如果没有声明虚析构函数,就不会调用派生类的析构函数,从而导致对象析构不完全造成内存泄漏。还有,并不是所有的析构函数都要声明为虚函数,只有在这个类意图作为一个基类时才需要为它声明虚析构函数,否则没有意义;

  • 如果类中声明了虚函数,那么类中会生成一张虚表,存放在静态区(全局区)的.rodata段,也就是只读数据段,对象的开头几个字节会设置为虚指针地址,根据这个地址找到虚表,然后调用虚函数。

8、 一个大文件中存了很多URL,如何找出相同的URL(应该是问找出重复出现过的URL)?

我直接不问条件,一口气讲完,请看标准答案:

一般来说遍历文件对每个URL建哈希表,就可以得出重复出现过的URL。但是对于大文件,有可能几十甚至几百个G,不可能对其建哈希表,因为内存放不下,像这种大文件数据处理首先是要想到分而治之,将其拆分成若干个小文件,具体拆分成多少个,取决于文件大小以及所给内存大小。比如我要拆分成1000个小文件,先遍历整个大文件,对其中每个URL做哈希计算,或者其他单向散列算法,计算出一个数值,将这个值对1000取模,最后得到的值作为小文件编号,该URL存入此编号的小文件,因为是单向散列算法,所有的URL都会较均匀的分布到这1000个小文件中。又因为相同的URL计算出来的散列值相同,所以相同的URL必定会分到同一个小文件内,这时只要逐个遍历小文件建立哈希表就可以得到相同的URL了,因为小文件的话内存是能够装下的。

9、 在函数中能返回局部变量的地址吗?返回后在main函数中是否能根据此地址取到该局部变量的值?

不能,因为局部变量在函数返回后就销毁了,再到它的地址去取值是没有意义的;

追问:为什么局部变量在函数返回后会销毁?

答:我想是因为局部变量是存储在栈上的,栈空间由系统来分配,当局部变量离开作用域,其内存空间就会自动被释放,只有用new或者malloc分配在堆上的空间才是不会被自动释放的。

10、 你目前还面试了哪些公司?

秋招的话,百度是我第一家面试的公司,目前还没有面其他公司。

算法题部分

  • 手撕反转链表

本来想一边说一边写,面试官说你写完再给我说思路,手撕了老半天,差点翻车,好在最后调出来了。解说的时候反转链表循环里的三条语句面试官没看明白,我又打开画图,蹩脚地进行画图讲解,面试官好像还是没听明白,沉默了一会儿,还是继续下一个题了,可能我画的不太好,越看越懵逼。完整代码以及当时我画的图如下:

#include <iostream>
using namespace std;
struct ListNode                            //链表节点的结构体
{
    int val;
    ListNode* next;
    ListNode() :val(0), next(nullptr) {}
    ListNode(int _val) :val(_val), next(nullptr) {}
    ListNode(int _val, ListNode* _next) :val(_val), next(_next) {}
};
ListNode* create(int n)                    //自动建立链表函数
{
    ListNode* dummy = new ListNode(0), * p = dummy;
    while (n--)
    {
        int tmp;
        cin >> tmp;
        p = p->next = new ListNode(tmp);
    }
    return dummy->next;
}
ListNode* reverseList(ListNode* head)      //反转链表函数
{
    if (head == nullptr) return nullptr;
    auto pre = head, cur = head->next;
    while (cur)
    {
        auto ne = cur->next;
        cur->next = pre;
        pre = cur, cur = ne;
    }
    head->next = nullptr;
    return pre;
}
int main()
{
    int n;
    cin >> n;
    ListNode *head = create(n);
    auto reverse_head = reverseList(head);
    auto p = reverse_head;
    while (p)                                //循环打印反转后的链表
    {
        cout << p->val << " ";
        p = p->next;
    }
    return 0;
}

反转链表画图.png

  • 手撕约瑟夫环问题

面试官问:“有N个小朋友排成一圈,轮流数k个数,数到k的那个小朋友出局,问最后剩下的是哪一个小朋友?想想用什么方法实现?”

我直接说这就是约瑟夫环问题(但是我忘了这题该怎么写了,好久之前刷过),于是我故意试探性地问是要写公式来实现吗?面试官说也可以写一下公式,我抓耳挠腮半天没想出来,请面试官给点提示,面试官说你想想其他实现方式吧,我说要写代码实现吗,面试官说那你写一下代码吧(绕了半天还是绕回来了,哭泣)。

我完全没思路,努力回忆当时力扣的题解是怎么做的,正当我要放弃说没思路的时候,面试官说不用想什么巧妙的解法,你就用最普通的方法想想,你会怎么做?

我突然想起来这题估计跟上一题有联系,继而想到可以用循环链表来实现,于是把上一题的代码改了改,写出来了。写完面试官说有内存泄漏,我赶紧添了个delete tmp。完整代码如下:

#include <iostream>
using namespace std;
struct ListNode                //链表节点结构体
{
    int val;
    ListNode* next;
    ListNode() :val(0), next(nullptr) {}
    ListNode(int _val) :val(_val), next(nullptr) {}
    ListNode(int _val, ListNode* _next) :val(_val), next(_next) {}
};
ListNode* create(int n)        //自动建立链表的函数
{
    ListNode* dummy = new ListNode(0), * p = dummy;
    while (n--)
    {
        int tmp;
        cin >> tmp;
        p = p->next = new ListNode(tmp);
    }
    p->next = dummy->next;    //尾节点接着头结点,构造循环链表
    return dummy->next;
}
void remove(ListNode* head, int k, int &n)    //删除第k个节点的函数
{
    while (k -- )
    {
        head = head->next;
    }
    auto tmp = head->next;
    head->next = head->next->next;             //跳过下一节点
    delete tmp;                                //防止内存泄漏
    --n;                                       //每次删除,总元素个数减1
}
int main()
{
    int n, k;
    cin >> n >> k;
    ListNode *head = create(n), *p = head;
    while (n != 1)                            //直到剩下一个元素为止
    {
        remove(p, k, n);
    }
    cout << p->val << endl;                   //输出这最后一个元素
    return 0;
}
  • 内存管理算法LRU思路

刚做过这个题,印象还有,我直接说了原理,然后说用哈希表+双链表实现,然后就说不下去了。

面试官说我应该先讲要实现哪些操作,再说具体实现。

我马上反应过来说主要实现插入和查找操作,哈希表大小就是内存大小,双链表最前面的元素就是最新的元素,最后的元素就是最久未使用过应该要淘汰的元素。如果插入时哈希表满了就把双链表尾部元素删除,新元素插入到双链表头,同时更新哈希表,如果插入时哈希表没满,直接将新元素插入双链表头部再更新哈希表即可。查询操作就把查询到的元素移动到双链表头部即可。

还好没让我手撕,这题手撕还是挺吃力的。

反问环节

  • 请问您所在的是百度哪一个部门?

百度阿拉丁。

我又问阿拉丁是什么,第一次听说。面试官巴拉巴拉说了一些,我当时没记住。

  • 请问您的部门主要用什么语言做开发?

GOPHP

我问那我进来也需要转GOPHP了,面试官问我对转语言有什么看法?

我说无所谓啊,语言只是工具而已,要转什么语言我都OK。

  • 您在面试的时候会比较看重求职者哪方面的能力呢?

我们最看重基础,以及把基础知识运用在解决实际问题上的能力。

总结

感觉现阶段确实没有必要花大力气去学RedisNginx这些东西,基础还是最重要的,简历上写了什么知识点,就把这些知识点记好。

二面(24min)8-18

二面是电话面,面试官迟到了38分钟,有点离谱,我都以为被放鸽子了。

1、问项目

问了老半天,然后说我实习项目技术含量不是很高呀,又评价我我聊天室项目说基本上任何一本讲网络编程的书都有吧,我只能苦笑说是的是的哈哈。

2、你在实习的这个项目中最大的收获是什么?

因为这是我第一次实习,我觉得收获最大的地方在于跟Leader沟通具体功能的实现,对接任务,提升一些业务上的能力。技术上的话,因为我之前没接触过QT,而实习项目是用QT做的,我觉得提升了自己快速学习一门新技术,并将其应用到实际开发中的能力。
这段是我当时现场编的,感觉答得还不错哈哈,确实也是如此。

2、了解MySQL、Redis吗?

我说不了解,没学过,又说了一堆我没听过的词,我说没听过,就没继续问了。

3、C++里面public、private和protected的区别?

突然问个那么简单的我有点诧异,按照常规思路答了。

4、MySQL底层索引怎么实现的?有什么优点和缺点?(这个问题一面已经问过了)

5、MySQL一张表能存多少数据?

我说不知道,不太了解。后来百度也找不到一个具体的解答,有点懵。

6、了解大文件处理吗?比如我有8G的内存,但是需要处理10G的文件,怎么处理?

大文件处理的话,首先应该是分而治之,要把它拆分成若干个小文件在放到内存中进行处理。

追问:那怎么保证拆分后相关的数据能放在同一个小文件中呢?比如每一行是一条数据,把相同类型的数据归到一个小文件中。

可以用哈希算法或者其他单向散列算法,对该条数据表示类别的那个字段进行计算,对计算出来的值模以10(比如要分成十个小文件),最终得到的值就是要存放这条数据的小文件的编号,这样一个大文件就会按类别较均匀地拆分成10个小文件,再进行处理。

总结

二面因为是电话面,问得比较简单,最后给我说过了,后面会通知我进行三面。这是我离offer最近的一次,求求了,让我过吧!

三面(34min)8-25

百度提前批只有三面,没有HR面,三面是经理面,如果经理是技术出身,那么还是会问很多技术问题,但我约面时被告知是电话面,所以肯定是非技术面了,应该就是聊人生。于是也做了一些HR面的准备。

1、问实习做什么?实习遇到最大的困难是什么以及如何解决?实习过程收获最大的是什么?

2、你觉得你跟科班出身的同学比有什么优势?

灵魂拷问,我当时是真不知道该如何答,我反问是指计算机或开发方面的优势吗?面试官说其他方面都可以,我赶紧将话题转移到其他方面:

  • 我善于观察和记录,因为平时有写日记的习惯,已经写了四年了,每天都写,所以每每遇到事情,无论大小我都会记录下来,这种习惯也延伸到工作中,每当解决一个问题,我都会详细记录,下次再遇到同样的问题能做到有据可查;
  • 我比较专心,当时考研考了两年,第二年是在家里复习的,最后考上了。所以我觉得自己有能专心学习,不受外界干扰的能力;
  • 快速学习的能力,实习所在的部门临时让我接手一个QT项目,但我之前不太了解QT,花了一个周末去学习,周一上班就开始做需求了,所以我觉得自己有快速学习一门新技术并将其应用到业务开发上的能力。

3、你的职业规划

短期的话我自己还是想做技术,多学一些技术栈,有时间也会往底层去学,感觉我还是想做技术吧,短期计划就以技术为主。

4、你不是计算机专业的,那你平时是怎么学习计算机的知识?如何规划的?

我还是以看书为主吧,我是去年10月份开始学的C++,到现在还没满一年。最开始也是看一些经典的书籍,配合一些技术博客,比如CSND等等,书与博客互补学习。

5、你还会用其他方式学习吗?

会,早期的时候还会看视频学习,比如B站,上面也有不错的学习视频。不过我觉得看视频太费时间了,讲得很啰嗦、抓不住重点甚至讲的是错的,后面我慢慢就不看视频了,转而看书,因为书是权威,肯定不会是错的。

6、刚才你提到了B站,你是如何看待B站的?你觉得B站为什么成功?

最开始我了解B站是因为它是一个二次元社区,我对这方面也比较感兴趣,但现在的B站已经不只是二次元了,有美食、科技、很多生活类、学习类的视频,是一个比较全面的网站;

首先是B站看视频没有广告吧,而且也不会有各种各样的弹窗,还有就是有激励计划,让很多新人积极参与到视频制作中来。

7、你用过抖音吗?说说B站和抖音的区别?

B站常用,但是抖音没用过。我觉得主要是用户群体不同吧,现在生活节奏快,大家都很忙,时间碎片化,所以短视频刚好可以用来填补这些碎片时间,而像B站这种动辄十几分钟甚至一个小时的视频往往是没有时间去看的。

8、刚才你提到了碎片时间,那你平时是怎么利用碎片时间的呢?

比如我在实习的时候,中午吃完饭还有一个小时的时间休息,除去睡午觉的半小时,剩下半小时我会打会儿游戏放松一下,或者看看自己的笔记,复习巩固,因为平时有用Markdown写笔记,有时间就会看一下。

9、你写的是什么笔记?笔记都是保存在本地的吗?

就是计算机的一些基础知识,计网、操作系统、数据结构这些,虽然书上和博客上都有,但我感觉需要自己总结一遍记下来,印象才会深。本地有存,我也经常在一个叫AcWing的算法网站上分享这些笔记,让更多人看到,或许大家会有不同意见,可以继续探讨。

10、你之前说自己对开发感兴趣,那么你为什么不本科毕业就出来做开发呢?既然感兴趣那你为什么不考计算机专业的研究生呢?为什么读了通信专业的研究生又来做开发?

本科的时候我就对程序设计挺感兴趣的,那时候自学了PHP,但当时感觉自己学得不是很精,可能没法找到好的工作,加上周围同学都考研,我就也去考研了;
当时考研也查过许多资料,因为自己没有系统学过计算机,直接跨考要补的东西太多,希望可能不是很大,所以选了比较稳妥的通信;
其实刚读通信研究生的时候我还是对学术抱有期望的,但是我发现通信专业的导师都不做通信的,全都在搞计算机,深度学习这些东西,我也开始往这个方向学。后来在一个师兄的建议下学起了C++,发现自己很感兴趣,就想以后也做开发了。

总结

其实这个环节我还是没有准备特别好,当时答得比较乱,每次不知道如何作答时都逼自己冷静,不要冷场,赶紧想想可不可以反问点什么东西。面完女经理加了我微信,不出意外的话应该能拿offer了!

9-13 OC

三面完晾了我18天,终于oc了,HR还打电话来问我能不能去实习,我说我正在另一家公司实习,去不了hh。坐等谈薪。