今天聊:大廠如何用一道編程題考察候選人水平

第三十屆|前端早早聊大會 BFF 專場 - 玩轉先後端接口(GraphQL、統一網關、API 接入、API 管理、協議轉換、統一安全切面、高併發處理、可視化編排、統一穩定性建設...)8-14 全天直播,9 位講師,報名上車看直播👉 ):javascript

海報.png

前端早早聊大會,與掘金聯合舉辦。加 codingdreamer 進大會技術羣,贏在新的起跑線, 全部往期都有全程錄播,上手年票一次性解鎖所有前端


正文以下

本文是第二十二屆 - 前端早早聊面試方法專場,也是早早聊第 157 場,來自盒馬高級專家-宗羽 的分享。java

自我介紹

image.png

進入正題

面試環節對面試官的一些挑戰

  • 面試官和候選人的知識結構可能有差別 => 可能會錯過優秀的人
  • 遇到「麪霸」,頻繁面試刷題,可是實際能力通常 => 招到不合適的人
  • 要在短短半個小時到一個小時內判斷一我的,其實很難

相對靠譜的作法

  • 筆試:"Talk is cheap, show me the code"

筆試常見的問題

  • 考通用算法,Google 能直接搜到,失去考察意義
  • 題目難度設計有問題。要麼滿分,要麼零分,可能錯過還不錯的同窗
  • 和實際工做內容脫節

我認爲好的筆試題

  • 上手門檻低,全部人多多少少都能寫一點,不至於開天窗
  • 考點多,經過一道題能夠基本摸清候選人的代碼綜合素養
  • 給高端的人有足夠的發揮空間。一樣的結果,不一樣的實現方式能夠看出候選人的技術深度

我經常使用的一道筆試題

很普通的一道題git

// 假設本地機器沒法作加減乘除運算,須要經過遠程請求讓服務端來實現。
// 以加法爲例,現有遠程API的模擬實現

const addRemote = async (a, b) => new Promise(resolve => {
  setTimeout(() => resolve(a + b), 1000)
});

// 請實現本地的add方法,調用addRemote,能最優的實現輸入數字的加法。
async function add(...inputs) {
  // 你的實現
}

// 請用示例驗證運行結果:
add(1, 2)
  .then(result => {
    console.log(result); // 3
});


add(3, 5, 2)
  .then(result => {
    console.log(result); // 10
})
複製代碼

答案一 最基本的答案,若是寫不出來,那大機率是經過不了了github

async function add(...args) {
  let res = 0;
  if (args.length <= 2) return res;

  for (const item of args) {
    res = await addRemote(res, item);
  }
  return res;
}
複製代碼

遞歸版本web

async function add(...args) {
  let res = 0;
  if (args.length === 0) return res;
  if (args.length === 1) return args[0];
  
  const a = args.pop();
  const b = args.pop();
  args.push(await addRemote(a, b));
  return add(...args);
}
複製代碼

常見的問題:面試

  • 沒有判斷入參個數
  • 仍然用了本地加法

答案二 有候選人的答案以下:算法

// Promise鏈式調用版本
async function add(...args) {
  return args.reduce((promiseChain, item) => {
    return promiseChain.then(res => {
      return addRemote(res, item);
    });
  }, Promise.resolve(0));

}
複製代碼

從這個實現能夠看出:後端

  • 對 Array.prototype.reduce 的掌握
  • 對於 Promise 鏈式調用的理解
  • 考察候選人對 async function 本質的理解

這個版本至少能到 70 分數組

答案三 以前的答案結果都是對的,可是咱們把耗時打出來,能夠看到耗時和參數個數成線性關係,由於全部計算都是串行的,顯然不是最優的解

更好一點的答案:

function add(...args) {
  if (args.length <= 1) return Promise.resolve(args[0])
  const promiseList = []
  for (let i = 0; i * 2 < args.length - 1; i++) {
    const promise = addRemote(args[i * 2], args[i * 2 + 1])
    promiseList.push(promise)
  }

  if (args.length % 2) {
    const promise = Promise.resolve(args[args.length - 1])
    promiseList.push(promise)
  }

  return Promise.all(promiseList).then(results => add(...results));
}
複製代碼

能夠看到很明顯的優化。

答案四 還能再優化嗎? 有些同窗會想到加本地緩存

const cache = {};

function addFn(a, b) {
  const key1 = `${a}${b}`;
  const key2 = `${b}${a}`;
  const cacheVal = cache[key1] || cache[key2];
  
  if (cacheVal) return Promise.resolve(cacheVal);
  
  return addRemote(a, b, res => {
    cache[key1] = res;
    cache[key2] = res;
    return res;
  });
}
複製代碼

加了緩存之後,咱們再第二次執行相同參數加法時,能夠不用請求遠端,直接變成毫秒級返回

還能再優化嗎?交給你們去思考

其餘考察點

有些時候會讓候選人將代碼提交到 Github 倉庫,以工做中一個實際的模塊標準來開發,能夠考察:

  • git 操做,commit 規範
  • 工程化素養
  • 是否有單元測試
  • 覆蓋率是否達標
  • 依賴的模塊版本如何設置
  • 如何配置 ci/cd
  • 文檔、註釋
  • ...

更加開放的一種筆試形式

  • 給一道題目,讓候選人建一個 Github 倉庫來完成
  • 題目有必定難度,可是能夠 Google,也能夠用三方模塊,和咱們平時作項目差很少
  • 一般面向級別較高的候選人

實際題目

// 有一個 10G 文件,每一行是一個時間戳,
// 如今要在一臺 2C4G 的機器上對它進行排序,輸出排序之後的文件

// 案例輸入
// 1570593273487
// 1570593273486
// 1570593273488
// …

// 輸出
// 1570593273486
// 1570593273487
// 1570593273488
// …

複製代碼

先看一個答案,看看哪裏有問題

async function sort(inputFile, outputFile) {
  const input = fs.createReadStream(inputFile);
  const rl = readline.createInterface({ input });
  const arr = [];
  for await (const line of rl) {
    const item = Number(line);
    arr.push(item);
  }
  arr.sort((a, b) => a - b);

  fs.writeFileSync(outputFile, arr.join('\n'));
}
複製代碼

10GB 的文件沒法一次性放進內存裏處理,內存只有 4GB

再看一個神奇的答案,只有一行代碼,並且從結果來講是正確的。但不是咱們筆試想要的答案。

const cp = require('child_process');

function sort(inputFile, outputFile) {
 cp.exec(`sort -n ${inputFile} > ${outputFile}`);
}
複製代碼

解題思路

  • 既然沒辦法一次性在內存中排序,那咱們可否將 10GB 的文件拆分紅若干個小文件
  • 小文件先分別排序,而後再合併成一個大的文件

再將問題拆解

  • 拆分大文件到小文件
  • 小文件在內存裏排序
  • 合併全部小文件成一個總體排序過的大文件

本題最難的點在於如何合併全部小文件。代碼如何實現?

  • 這裏須要用到一種數據結構:堆
  • 堆:就是用數組實現的一個二叉樹
  • 堆分爲:最大堆和最小堆,下面是一個最小堆(父節點小於它的子節點)

image.png

堆有一些特性:

  • 對於一個父節點來講
    • 左節點位置:父節點位置 * 2 + 1
    • 右節點位置:父節點位置 * 2 + 2
  • 很容易查找最大值 / 最小值

咱們嘗試把下面數組構形成一個最小堆

image.png

  • 從最後一個非葉子節點開始往前處理
  • 10 比 5 大,因此交換它們的位置

image.png

  • 而後是節點 2,符合要求不須要處理
  • 最後到頂點 3,它比左子節點大,因此要交換

image.png

完整的實現參考:github.com/gxcsoccer/e… image.png

介紹盒馬體驗技術部目前作的一些事情

  1. 盒做社:多媒體創意生產平臺
  2. REX Design:盒馬設計體系
  3. 跨端(PC/Phone/Pad/POS...)
  4. 高性能:相比於 Antd 提供支持虛擬滾動的表格、Tree、Select 等組件
  5. 零售業特點組件:地圖排線、排班、交叉表、透視表、特點可視化
  6. 工業控制(AIOT 相關):數字化養蝦
  7. 數盒:零售業特色的數據分析和可視化
  8. ...

面試流程

image.png

推薦的書—《數據分析思惟》

「數據分析不是某個固定的職位,而是人工智能時代的通用能力」

image.png


第三十屆|前端早早聊大會 BFF 專場 - 玩轉先後端接口(GraphQL、統一網關、API 接入、API 管理、協議轉換、統一安全切面、高併發處理、可視化編排、統一穩定性建設...)8-14 全天直播,9 位講師,報名上車看直播👉 ):

相關文章
相關標籤/搜索