# 一、前言

实际上在投这家公司之前,我对于电动车或者是车这一块实在是没有了解过,也没有兴趣去了解,以至于在后面反问的阶段他问我关于电动车的看法我都支支吾吾讲不出多少。

不过一面面试官还是非常好非常好的,有开摄像头,整个人的语气听起来就是一个很和蔼的大哥哥(点名批评古茗面试官),以至于全程都是跟聊天一样,氛围很轻松,因此发挥的也比较好。

二面面试官更多是比较严肃的提出一些对于项目、博客之类的一些问题,以及分享一些经验,人也是比较好的。

HR 面基本都是问一些关于我自己个人的信息,以及询问对于蔚来这家车企的了解等等。偏向纯聊天,在这里暂且不记录了。

目前蔚来 NIO 已经 OC,准备收拾行李出发去上海了嘿嘿

# 二、题目列表

# 一面

  1. 自我介绍 + 项目介绍,在项目方面主要和我探讨了 WST-Render 这个我在目前公司里面实现的一款内部用的 Markdown 编辑器,详细介绍了从 code 转换为 DOM 的过程以及主要由我负责的 同步滚动 功能的实现(单这一个功能就讲了 20min)。

    另外这个面试官提了一个非常刁钻的问题:既然你目前的渲染组件都是自己通过现成的 Markdown 语法去进行匹配编写的,那么我如果想要在目前的这个渲染区域直接嵌入一个我编写好的一个 Vue 组件只做预览使用,这样子的话又要怎么根据自定义语法去进行组件的引入呢?

    一开始我还以为是类似于 qiankun 这样的微前端的玩意,结果面试官提示说 直接在进行 AST 编译转换的过程中把对应的现成组件进行引入即可 。后来问了一下,原来他们内部就有实现过这样一款类似的工具,真是小巫见大巫了。

    可能是我的项目比较合面试官的胃口,聊项目就聊了 40min 左右。

  2. 算法题:典中典之动态规划之典中典 354. 俄罗斯套娃信封问题,想看题目的同学直接点力扣链接,就是 100% 纯粹的原题。

    我当时没写出来,只是和面试官探讨了一下相关的解法,因为当时还没刷到这个题,面完之后就立马被我刷到了。

    给一下 TS 版本的解法, 实际上就是数据预处理 + 求最长公共子序列问题

    function maxEnvelopes(envelopes: number[][]): number {
      // 数据预处理:按宽度升序排序,如果宽度一样,则按高度降序排序
      envelopes.sort((a, b) => (a[0] === b[0] ? b[1] - a[1] : a[0] - b[0]));
      // 着眼于高度,求最长递增子序列即可
      const heights = envelopes.map((item) => item[1]);
      const lengthOfLIS = (nums: number[]) => {
        const dp = new Array(nums.length).fill(1);
        for (let i = 0; i < nums.length; i++) {
          for (let j = 0; j < i; j++) {
            if (nums[j] < nums[i]) {
              dp[i] = Math.max(dp[i], dp[j] + 1);
            }
          }
        }
        return Math.max(...dp);
      };
      return lengthOfLIS(heights);
    }
  3. 算法题:给你一个全是数字的元素个数为 n 的数组,其中必定有一个数字的个数占比超过 n/2 向上取整。找出这个数字总共可以用多少种方法?

    1. 摩尔投票算法(Moore's Voting Algorithm)
      这是一种高效的线性时间复杂度算法。它的基本思想是维护一个候选人和一个计数器,遍历数组时,如果当前元素与候选人相同,则计数器加一,否则减一。如果计数器变为零,则更换候选人为当前元素。最终剩下的候选人就是大于 n/2 的数字。
    function findMajorityElement(nums: number[]): number {
      let candidate = 0;
      let count = 0;
      for (let num of nums) {
        if (count === 0) {
          candidate = num;
          count++;
        } else if (num === candidate) {
          count++;
        } else {
          count--;
        }
      }
      return candidate;
    }
    1. 排序
      将数组排序,然后直接取中间位置的元素即可。由于题目规定一定存在大于 n/2 的数字,所以中间位置的元素一定是所求。
    function findMajorityElement(nums: number[]): number {
      nums.sort((a, b) => a - b);
      return nums[Math.floor(nums.length / 2)];
    }
    1. 哈希表
      使用哈希表统计每个数字的出现次数,然后找出出现次数大于 n/2 的数字。
    function findMajorityElement(nums: number[]): number {
      const freqMap: Map<number, number> = new Map();
      for (let num of nums) {
        freqMap.set(num, (freqMap.get(num) || 0) + 1);
        if (freqMap.get(num) > nums.length / 2) {
          return num;
        }
      }
      // In case no majority element found
      return -1;
    }

​ 当时答出了后面两种方法,第一种方法没有事前了解过是比较难在面试当中现场想出来的。

# 二面

二面换了个面试官,语气很明显的没有一面面试官这么好了,说的话都比较凌厉,因此我也基本不笑呵呵了,比较严肃的面对这个面试官。不过出乎意料,基本上是纯聊天,单纯问我项目 + 学习 + 自己的项目运营。等我介绍完毕后,居然来一句 “我听过来感觉你的技术实力还是比较过硬的,我就不考你代码题了。” 代码题才是我最最最薄弱的地方啊喂!就这么逃过了一劫。

首先还是自我介绍 + 聊项目,项目主要聊的是我参与的一个脚手架开源项目 Create-Neat,我就介绍了自己在这个项目中担任的角色、实现的功能等。

叽里呱啦的讲完后,面试官居然真的现场打开了我的 github 主页去找我是否有参与这个项目,并且还进去查看了一下我的 contribution ,结果因为分支太多了找不到我负责的那部分,然后就这部分争论了比较久。不过幸好除了这个项目外,面试官又看到了我仓库里面的其他项目,然后就聊到其他部分了。

然后就是聊我的个人博客,以及我在其他平台写的一些技术文章等等,聊的挺久,他也提供了很多写作的经验。看得出来人也是比较好的。

聊完之后,直接跳过八股 + 代码,进入反问阶段。其他部分没什么好讲的,不过在反问部分居然问了我一句 “你是二次元吗?”

当时两眼一黑,为什么问我这个?结果说 我看你博客很多女孩子,我就觉得你爱好跟我们这挺相似的。

什么时候二次元都成为加分项了!!

最后面试官说,他们这边虽然是做的一些面向他们智能驾驶系统的一些 ToB 项目,但是他们公司内部也有专门针对某个需求特地去研发内部使用的一些纯技术工具,我也是对这方面相对比较感兴趣。并且他们内部也有实现一个内部组件库,几乎用在所有的管理系统当中。

不过对我个人而言,还是想多做一些技术相关的东西。

# 三、结语

目前蔚来这边已经 OC 了,也拒掉了其他大厂的一些 offer。整体的面试氛围以及收获也是相对比较大的。希望接下来的时间能够在蔚来有所收获吧!