纪录我的春招之路 (持续更新到找到实习)

写在前面

大三了,所以该找找实习了,用这个文章记录一下在各个面试中遇到的问题和总结,希望可以早日好的找到实习。。

腾讯

一面

  1. 指针和引用;定义和声明;内存泄漏和内存溢出;堆和栈的区别
  2. PHP垃圾回收机制
  3. 进程,线程讲一下
  4. MySQL常用引擎及其区别
  5. 索引相关,底层实现,B树和红黑树
  6. MySQL优化,问了很多
  7. MySQL死锁出现原因及解决方法
  8. 各种排序的时间复杂度,稳定性,空间复杂度
  9. TCP三次握手,四次挥手
  10. awk的使用
  11. HTTP的常用状态码,请求方法
  12. IO多路复用,它们的区别
  13. https中证书内都存放哪些内容
  14. 手写代码:洗牌,发牌算法

    二面

  15. IPC通信的各种机制,越详细越好,哪种开销最小,为什么
  16. 进程的内存分配
  17. 用户态,核心态。为什么要区分,OS是怎么做到区分的,什么情况下会发生切换
  18. 进程,线程问了很多很多,具体记不清楚了
  19. MySQL主从复制
  20. 事务,储存引擎,联合索引,最左前缀原则
  21. Redis的LRU算法实现,集群,哨兵机制,数据类型,各个数据类型的底层实现
  22. 手写代码: a.堆排序 b.双向链表转排序二叉树,不能申请新空间 c.快排及其优化方法
  23. https过程,证书认证是怎么做的
  24. RSA加解密过程,RSA签名,使用时有什么需要注意的点
  25. TCP三次握手,四次挥手,为什么是四次,TIME_WAIT状态相关。SYN洪泛攻击怎么解决
  26. 分布式事务
  27. 幂等性
  28. 在确保幂等性时,前端防抖是怎么做的
  29. 逻辑题目:用几个不同容积的水桶分水的题目。。具体数字不记得了
  30. PHP怎么实现弱类型,7.0版本在这方面和之前的版本有什么不同
  31. Web安全的常见漏洞,CSRF,XSS,注入
  32. select和epoll
  33. Linux命令, a. 查看内存使用 b.查看某个进程使用的系统调用 c.awk编程
  34. 缓存穿透,缓存雪崩的预防方法,布隆过滤器

搜狗

  1. Cookie相关,set-cookie函数的用法,原理。
  2. HTTP协议Request和Reponse包的结构和内容。
  3. 301和302的区别,Location字段的含义。
  4. 布隆过滤器。
  5. 内存对齐。
  6. B+-Tree结构,前缀索引为什么可以使用到索引。
  7. c10k问题。
  8. 手写代码,多叉树的层序遍历。
  9. PHP7的特性和优化。
  10. PHP的协程。

小米

  • 电话面试,感觉还好,有一些问题确实没有了解过,也没有办法。。有没有后续就还不知道了。
  • 项目相关,说了说寒假实习公司的项目和自己做的两个开源的小东西。。
  • MySQL中的常用优化手段:
    1. 避免select *
    2. 提高索引选择性,索引选择性 = 不重复的索引值/数据表记录总数
    3. 使用多列索引并选择更加合适的索引顺序。在不考虑排序和分组时,将选择性最高的索引放在索引最前列
    4. 遵循最左前缀原则,保证索引不失效
    5. 在遇到慢查时,使用explain关键字查看语句运行情况
    6. 各种小的点,比如有between代替in,limit优化,自查询优化等等。
  • 使用Explain语句时,你会关注哪些信息,这些信息都表示什么。。。只答出了自己记着的
    1. type字段,该字段表示索引使用情况,最差是all,最好是system。
    2. rows字段,表示MySQL引擎执行计划中估算的扫描行数,如果该数值过大,就表示有可能索引失效或者索引选择性不够高,应该对索引顺序进行调整。
    3. key字段,真正用到的索引。
  • MySQL中的隔离级别,你使用的是哪一级别
    1. 未提交读,最低的级别, 会造成脏读。
    2. 提交读,个事务从开始到提交,所做的任何修改对其他事务都是 不可见的。
    3. 可重复读,MySQL默认的隔离级别,解决脏读,但可能出现幻读。
    4. 可串行化:最高的级别,解决幻读。
    5. 自己都是使用默认的,并没有做过修改。。。。
  • 如果两个事务同时读取一行数据,是否会阻塞
    • 不会,读锁是共享锁,写锁是排他锁,所以在读取时并不会阻塞其他事务
  • 那如果我要强制阻塞呢
    • 我只知道可以显式地添加一个排他锁。。但是怎么做给忘了。。面完之后查了一下,好像是用for update可以加一个排他锁。。
  • 索引默认是基于什么数据结构实现的,为什么
    • 基于B-Tree或B+Tree实现的,至于为什么,自己只知道是因为B-Tree结构可以既满足了平衡二叉树在查找时的高效率,又相对于红黑树等其他平衡树来说,它的树高很低,可以大大减少I/O次数,节省时间。具体的就不知道了,后面再查查学一下。
  • 那B-Tree和B+Tree有什么区别啊
    • B+Tree会在叶子节点储存具体的数据信息,B-Tree不会。。。只知道这个?
  • 了解聚簇索引嘛,说一说
    • 聚簇索引是一种数据储存方式,当有聚簇索引时,,数据行实际存放在索引的叶子节点中,聚簇索引可以大量减少磁盘I/O,提高访问速率。但是插入和更新的代价都很大。
  • PHP是弱类型语言,它是怎么实现弱类型的
    • maya...这也太底层了吧。自己知道的只是PHP的Zval结构,每个变量在zend引擎层面都会维护一个Zval结构体。在Zval这个结构体中包含有引用计数,是否为引用,还包含有这个变量的具体的数据类型和值,只是在具体使用的时候没有暴露出来而已。。。这快确实懂得不多,还要多看看底层的知识。
  • 那如果让你来实现PHP的这个特性,你会选择什么数据结构
    • 我。。。。。我会选择结构体吧(因为我貌似记得PHP底层就是结构体吧)。
  • 为什么是结构体而不是联合体,结构体和联合体有什么区别
    • C语言的知识,但是给忘记了?。。就直说了不知道。
  • 在操作系统中,进程的调度算法都有什么。
    • 就在嘴边的知识,就是想不起来了,面完之后才想起来了有先来先服务,短作业优先,时间片轮转,高响应比,多级反馈队列。。
  • 死锁的条件
    • 下面有,就不重复了。
  • 银行家算法知道吗
    • 银行家算法可以通过预估资源分配,防止系统进入不安全状态的方法来避免死锁,自己在操作系统学习的时候,也做过相关实现。
  • 写一个算法题目吧,有两个操作,一个是给一个数乘以2,一个是给一个数减1,给定两个数字A和B,求出将A通过前面两个操作变成B的最少步骤。例如,A是4,B是6,则可以A乘2减1减1,也可以A减1再乘2,所以其最少步骤就是2。。

    • 最讨厌的算法题目又来了。真想抽死自己,竟然说成了深度优先遍历,面试官还好心的提示问了下是深度优先还是广度优先,然后自己范傻又说了是深度优先。。
    • 具体代码:
      function bfs($a, $b)
      {
      //结果数组
      $mask = [$a => 0];
      //队列
      $queue = [$a];
      while(!empty($queue)) {
              //出队
              $A = array_shift($queue);
              if ($A == $b) {
                      return $mask[$A];
              }
              $C = $A * 2;
              if (!isset($mask[$C])) {
                      $mask[$C] = $mask[$A] + 1;
              }
              //入队
              $queue[] = $C;
              $C = $A - 1;
              if (!isset($mask[$C])) {
                      $mask[$C] = $mask[$A] + 1;
              }
              //入队
              $queue[] = $C;
      }
      return false;
      }
  • HTTP的头部常用字段都有哪些,说出你知道的。
    • 只说出了一部分的
    • Cache-Control 控制缓存的行为
    • Connection 连接管理
    • Content系列,Type,Length之类的
    • UA HTTP客户端程序的信息
    • Host 请求资源所在服务器
    • Referer 对请求中 URI 的原始获取方
    • 太多了,就没说完,可以参考这篇文章,写得很不错
  • Connection字段是干什么的,有什么特殊作用
    • 在HTTP1.1中默认采用keep-alive保持长链接,已避免每次请求都要建立TCP连接所带来的消耗。
  • 如果在一个页面中,有一个请求是用了keep-alive,那么后面的请求会有什么影响嘛?
    • 这个真的不知道,就说了一下其他的,说了如果是在最新的HTTP/2中,由于其是比特流协议,所以可以多个请求进行多路复用。而在HTTP1.1中,我所能想到的只是如果是一个页面的话,它能同时发起的请求数量是有限制的。。。感觉完全没答到点上。。

今日头条

  • 头条的面试真的好难好难,上来就考算法,手撕代码,这又是自己最大的弱项,所以很明显的挂掉了。。。。
  • 手写代码题目1:
    /*
    * 有n个房间,现在i号房间里的人需要被重新分配,分配的规则是这样的:先让i号房间里的人全都出来,
    * 接下来按照 i+1, i+2, i+3, ... 的顺序依此往这些房间里放一个人,n号房间的的下一个房间是1号房间,直到所有的人都被重新分配。
    * 现在告诉你分配完后每个房间的人数以及最后一个人被分配的房间号x,你需要求出分配前每个房间的人数。数据保证一定有解,若有多解输出任意一个解。
    *
    *
    * 最先想到的是爆破的思路:从最后一个人被分配的房间开始往前递推,每个房间减一个人,直到某个房间人数减为0,但是并不是最优解法。。。
    * 面试完想到了另一种解法是找到分配后各个房间人数的最小值便是起始的i号房间。最小人数就是重新分配的轮次数。
    * */
    function findRoom($n, $x, $room)
    {
        $min = min($room);
        $index = function ($i) use($n) {
                return $i >= 0?$i % $n:$i % $n + $n;
        };
        //从最后分配房间回退到前一轮的i号房间
        for ($i = $x - 1, $d = 0;$min != $room[$index($i)]; $i --, $d ++ ) {
                $room[$index($i)] -= $min + 1;
        }
        //i号房间原人数
        $room[$index($i)] = $min * $n + $d;
        if ($index($i) != $x) {
                //恢复其它房间人数
                for ($i = $i - 1; $index($i) != $x; $i --) {
                        $room[$index($i)] -= $min;
                }
                $room[$index($i)] -= $min;
        }
        var_dump($room);
    }
  • 手写代码题目2

    /*
    * 打印二叉树从左视角看到节点
    * 给定一颗普通二叉树,请输出二叉树左视角能看到的节点
    * 例如,普通二叉树
    *                  1
    *               /       \
    *             2          3
    *          /    \      /     \
    *         4      5    6       7
    *                            /
    *                          8
    * 从左边看,输出能看到的 1,2,4,8 这四个节点。
    * 使用层序遍历,从右到左,然后将最左侧放入结果集中
    * */
    class Node{
        public $val, $left, $right;
        public function __construct($val)
        {
                $this->val = $val;
        }
    }
    function leftView($root)
    {
        $stack = [];
        $stack[] = $root;
        $ret = [];
        while (!empty($stack)) {
                foreach ($stack as $eachNode) {
                    $leftNode = array_shift($stack);
                    if (!empty($leftNode->right)) {
                            $stack[] = $leftNode->right;
                    }
                    if (!empty($leftNode->left)) {
                            $stack[] = $leftNode->left;
                    }
                }
                $ret[] = $leftNode->val;
        }
        var_dump($ret);
    }
    • Redis的优点和缺点?
      • 上面两道算法都基本没做出来,导致心态大崩,所以答得也不是很好,优点就是围绕着Redis的几个特性和数据结构及其应用场景,持久化,哨兵,集群来说明的,缺点就只说了它并不能完全容错和恢复,下面仔细记录学习一下。
      • 优点:
        1. 数据存放在内存中,读写速度很快,采用单线程结构,防止了因多线程竞争可能出现的问题和消耗。
        2. 数据类型丰富,五种基础数据类型,并且有很多很有用的扩展数据类型,如位图,HyperLogLog,发布订阅,GEO等。
        3. 功能丰富,提供键过期,简单事务,Lua脚本管理,Pipeline等功能。
        4. 数据可持久化,可通过RDB和AOF两种方式进行数据持久化。
        5. 提供主从复制,可利用集群,哨兵构建高可用的分布式架构。
      • 缺点:
        1. 不具备自动容错和恢复功能。
        2. 主机宕机,宕机未同步到从机的数据无法恢复。
        3. 主从复制采用全量复制,若快照文件过大,对集群的服务能力会产生较大影响。
        4. 难以支持在线扩容。
  • 死锁产生的条件:

    1. 互斥请求
    2. 不可剥夺
    3. 循环等待
    4. 请求保持
  • 进程和线程的区别:

    • 进程是资源拥有的基本单位,线程是CPU调度和分派的基本单位。
    • 一个程序至少有一个进程,一个进程至少有一个线程。
    • 进程在执行程序中拥有独立的内存单元,而多个线程共享内存,从而极大地提高程序的运行效率。
    • 进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。
  • 假如现在有50M的数据,网络延迟为50ms,仅考虑TCP的情况下,请预估一下将这个数据从北京发往深圳所需要的时间。
    • 听完我....一脸懵逼啊。。然后就只能扯了一下TCP从客户端发送数据再到服务端接收处理的整个处理过程,感觉面试官也很不满意。
    • 个人感觉这个问题的考点在于TCP传输中会将数据进行分段,每一段的最大长度是有限的,减去TCP头部长度便是每段的可发送的数据长度,然后在进行计算,但当时心态已经被算法题搞崩了就没心思再思考了。
    • 也顺便求一波答案,想了很久还是没明白,先谢过各位啦........

本文章首发在 Laravel China 社区