前端模擬面試:七個(gè) JavaScript 數(shù)組進(jìn)階面試題
你坐在面試室里,對(duì)面的面試官微笑著,輕敲著桌面問道:“那我們來聊聊 JavaScript 吧。數(shù)組操作你有多熟悉?”你意識(shí)到,眼前這個(gè)問題看似簡單,但面試官可能在考察你對(duì) JavaScript 基礎(chǔ)知識(shí)的深度掌握和靈活運(yùn)用。你深吸一口氣,準(zhǔn)備好好展示一番,從最常見的查找最大值問題入手,一步步展示自己的思路。
你知道,這不僅是一次技術(shù)能力的測試,更是一次展示你對(duì)問題解決思維的機(jī)會(huì)。于是,你信心十足地開始了……
面試題 1:如何找到數(shù)組中的最大值?
場景引入:你坐在面試官對(duì)面,面試官提出了一個(gè)基礎(chǔ)問題:“給定一個(gè)數(shù)字?jǐn)?shù)組,如何找出其中的最大值?” 你點(diǎn)點(diǎn)頭,快速思考了一下,準(zhǔn)備向面試官展示你對(duì) JavaScript 內(nèi)置方法的理解。
方法一:使用 Math.max 和展開運(yùn)算符
這是最直接的解決方案。你向面試官解釋說,可以使用 Math.max,并通過展開運(yùn)算符將數(shù)組元素傳遞進(jìn)去。這樣不僅語法簡潔,而且邏輯也很清晰。
const numbers = [1, 5, 3, 9, 2];
function findLargest(arr) {
return Math.max(...arr);
}
console.log(findLargest(numbers)); // 輸出:9
解析:在這里,Math.max(...arr) 將數(shù)組解包成單個(gè)參數(shù)傳入 Math.max,一行代碼就能返回最大值。面試官對(duì)此表示認(rèn)可,但也追問了一句:“如果數(shù)組很大,這種方法還適用嗎?”
你解釋說,展開運(yùn)算符可能會(huì)在大數(shù)組上有性能問題,因?yàn)樗鼤?huì)消耗較多的內(nèi)存。在百萬級(jí)別的數(shù)組上,更推薦使用 for 循環(huán)。
方法二:使用 for 循環(huán)逐一比較
為了展示自己對(duì)算法效率的考量,你提出了使用 for 循環(huán)的方式。你解釋說,雖然這看起來不像是“最簡單”的方法,但它能夠處理任何長度的數(shù)組,無論多大,都不會(huì)受到展開運(yùn)算符帶來的內(nèi)存限制。
你展示了如下代碼:
const numbers = [1, 5, 3, 9, 2];
function findLargest(arr) {
let max = arr[0];
for (let i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
}
console.log(findLargest(numbers)); // 輸出:9
解釋:在這個(gè)例子中,我們通過 for 循環(huán)從頭遍歷數(shù)組,將當(dāng)前最大值保存在 max 中。當(dāng)遇到更大的值時(shí),更新 max。這種方法在時(shí)間復(fù)雜度上是 O(n),而且不會(huì)引發(fā)內(nèi)存溢出,是一種更加穩(wěn)妥的處理方式。
面試題 2:如何找到數(shù)組中的第二大值???
場景引入:面試官接著問道:“如果要找到數(shù)組中的第二大值呢?” 你知道這是對(duì)算法理解的進(jìn)一步考察,于是準(zhǔn)備向面試官展示幾種不同的方法。
方法一:排序后取第二大值
你解釋說,最直觀的方法就是將數(shù)組降序排列,然后取第二個(gè)值。
const numbers = [1, 5, 3, 9, 7];
function secondLargest(arr) {
let sorted = arr.sort((a, b) => b - a);
return sorted[1];
}
console.log(secondLargest(numbers)); // 輸出:7
分析:數(shù)組排序后,sorted[1] 就是第二大值。不過排序的時(shí)間復(fù)雜度為 O(n log n),且會(huì)改變原數(shù)組,不是最高效的方法。
方法二:遍歷找到第二大值
如果希望更高效,可以在一次遍歷中找到第二大值。你解釋說,使用兩個(gè)變量 max 和 secondMax 來記錄最大值和次大值,可以在不排序的情況下得到結(jié)果。
const numbers = [1, 5, 3, 9, 7];
function findSecondLargest(arr) {
let max = -Infinity;
let secondMax = -Infinity;
for (let num of arr) {
if (num > max) {
secondMax = max;
max = num;
} else if (num > secondMax && num < max) {
secondMax = num;
}
}
return secondMax;
}
console.log(findSecondLargest(numbers)); // 輸出:7
解釋:這段代碼在一次循環(huán)中完成,時(shí)間復(fù)雜度為 O(n)。max 記錄當(dāng)前最大值,secondMax 記錄次大值。每次遇到新的最大值時(shí),更新這兩個(gè)變量,保證 secondMax 是最大值之外的最大元素。
面試題 3:如何去除數(shù)組中的重復(fù)項(xiàng)???
場景引入:面試官進(jìn)一步詢問,“能寫一個(gè)函數(shù)來去除數(shù)組中的重復(fù)項(xiàng)嗎?” 你知道這個(gè)問題在實(shí)際開發(fā)中很常見,立刻想到了用 Set 去重的方法。
方法:使用 Set 去重
使用 Set 是最快捷的方式,Set 會(huì)自動(dòng)去除重復(fù)元素。你向面試官展示了以下代碼:
const numbers = [1, 2, 2, 3, 4, 4, 5];
function removeDuplicates(arr) {
return [...new Set(arr)];
}
console.log(removeDuplicates(numbers)); // 輸出:[1, 2, 3, 4, 5]
解析:在這里,Set 自動(dòng)去重,然后再用展開運(yùn)算符將 Set 轉(zhuǎn)換回?cái)?shù)組。操作簡單且性能優(yōu)越,特別適用于中小規(guī)模的數(shù)據(jù)處理。
面試題 4:如何合并兩個(gè)有序數(shù)組并保持有序???
場景引入:接下來,面試官問你如何將兩個(gè)已排序的數(shù)組合并并保持順序。你知道,concat 和 sort 是一種快速實(shí)現(xiàn)的方式,適合面試展示。
方法:使用 concat 和 sort
const arr1 = [1, 3, 5];
const arr2 = [2, 4, 6];
function mergeArrays(arr1, arr2) {
return arr1.concat(arr2).sort((a, b) => a - b);
}
console.log(mergeArrays(arr1, arr2)); // 輸出:[1, 2, 3, 4, 5, 6]
解釋:concat 拼接數(shù)組,然后用 sort 進(jìn)行升序排列。這種方法簡單直觀,但如果有大量數(shù)據(jù)時(shí),concat 的內(nèi)存消耗和 sort 的效率需要注意。
面試題 5:如何旋轉(zhuǎn)數(shù)組???
場景引入:面試官看著你,提出一個(gè)稍微有點(diǎn)棘手的問題:“寫一個(gè)函數(shù),將數(shù)組右移 k 次?!蹦阋庾R(shí)到,這要求數(shù)組中的每個(gè)元素向右“移動(dòng)”指定的次數(shù)。比如,給定 [1, 2, 3, 4, 5],右移 2 次后數(shù)組應(yīng)變成 [4, 5, 1, 2, 3]。
這類旋轉(zhuǎn)操作在數(shù)據(jù)處理和算法應(yīng)用中十分常見。你腦海中浮現(xiàn)出一個(gè)思路:可以通過 slice 和 concat 兩個(gè)方法巧妙地完成旋轉(zhuǎn)。于是,你自信地向面試官展示了這段代碼。
方法解析:使用 slice 和 concat 拼接旋轉(zhuǎn)后的數(shù)組
你寫下了代碼,解釋道:
const arr = [1, 2, 3, 4, 5];
function rotateArray(arr, k) {
k = k % arr.length; // 防止 k 超出數(shù)組長度
return arr.slice(-k).concat(arr.slice(0, -k));
}
console.log(rotateArray(arr, 2)); // 輸出:[4, 5, 1, 2, 3]
代碼詳解:
(1)處理超長旋轉(zhuǎn)次數(shù):首先,k = k % arr.length 這一行確保旋轉(zhuǎn)次數(shù)不會(huì)超出數(shù)組長度。你解釋道,比如當(dāng) k = 7 時(shí),這段代碼將 k 變?yōu)?nbsp;2(7 % 5 = 2),這相當(dāng)于只旋轉(zhuǎn)了 2 次,避免了多余的操作。
(2) 分割數(shù)組:接下來,用 slice 方法將數(shù)組分成兩個(gè)部分,分別取出數(shù)組的尾部和前面的部分:
- arr.slice(-k) 用來取出數(shù)組最后 k 個(gè)元素。比如當(dāng) k = 2 時(shí),arr.slice(-2) 會(huì)返回 [4, 5]。
- arr.slice(0, -k) 則獲取數(shù)組的前面部分,不包括最后 k 個(gè)元素。對(duì) [1, 2, 3, 4, 5] 使用 arr.slice(0, -2),結(jié)果就是 [1, 2, 3]。
(3) 拼接旋轉(zhuǎn)后的數(shù)組:最后,你用 concat 將這兩個(gè)部分組合起來,把尾部的 [4, 5] 放到 [1, 2, 3] 的前面,完成右移操作。整個(gè)代碼執(zhí)行后得到 [4, 5, 1, 2, 3],實(shí)現(xiàn)了右移 2 次的效果。
舉例說明
你接著向面試官詳細(xì)說明:
假設(shè) arr = [1, 2, 3, 4, 5],k = 2。我們需要將數(shù)組右移 2 次,讓 [4, 5] 出現(xiàn)在數(shù)組開頭。
- 使用 slice(-2) 得到 [4, 5]。
- 使用 slice(0, -2) 得到 [1, 2, 3]。
- 把這兩個(gè)部分拼接起來,得到最終的 [4, 5, 1, 2, 3]。
關(guān)鍵點(diǎn)總結(jié)
- 循環(huán)優(yōu)化:通過 k % arr.length 確保旋轉(zhuǎn)次數(shù)不會(huì)超過數(shù)組長度,從而優(yōu)化效率。
- 分割和拼接:利用 slice 和 concat 組合,可以輕松實(shí)現(xiàn)數(shù)組的旋轉(zhuǎn)效果。
這段代碼不僅展示了如何高效地旋轉(zhuǎn)數(shù)組,同時(shí)也展現(xiàn)了你在面試中對(duì)細(xì)節(jié)的考量和巧妙的思路。面試官滿意地點(diǎn)點(diǎn)頭,對(duì)你的答案非常認(rèn)可。
面試題 6:如何判斷兩個(gè)數(shù)組是否相等???
場景引入:面試官繼續(xù)追問,“寫個(gè)函數(shù)來判斷兩個(gè)數(shù)組內(nèi)容是否完全一致?!?你知道,這不僅要內(nèi)容相同,還要順序一致。
方法:逐個(gè)元素比較
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];
function arraysEqual(arr1, arr2) {
if (arr1.length !== arr2.length) return false;
for (let i = 0; i < arr1.length; i++) {
if (arr1[i] !== arr2[i]) return false;
}
return true;
}
console.log(arraysEqual(arr1, arr2)); // 輸出:true
console.log(arraysEqual([1, 2, 3], [1, 2, 4])); // 輸出:false
解析:逐個(gè)元素對(duì)比可以確保內(nèi)容和順序一致。此方法適用于小型數(shù)組,因?yàn)闀r(shí)間復(fù)雜度為 O(n)。
面試題 7:如何找到數(shù)組中和為特定值的所有數(shù)對(duì)???
場景引入:最后,面試官拋出一道更復(fù)雜的問題:“找到數(shù)組中所有和為特定值的數(shù)對(duì)?!?這涉及到去重和優(yōu)化算法的問題。你準(zhǔn)備展示 Set 來解決這類查找問題。
方法:使用 Set 記錄和查找補(bǔ)數(shù)
const arr = [1, 2, 4, 3, 5, 7, 8, 9];
const target = 10;
function findPairs(arr, target) {
let result = [];
let seen = new Set();
for (let num of arr) {
let complement = target - num;
if (seen.has(complement)) {
result.push([num, complement]);
}
seen.add(num);
}
return result;
}
console.log(findPairs(arr, target)); // 輸出:[[3, 7], [2, 8], [1, 9]]
解析:通過 Set 記錄遍歷過的數(shù),找到符合條件的數(shù)對(duì)。利用查找補(bǔ)數(shù)的方式,避免重復(fù)數(shù)對(duì),且比雙重循環(huán)效率更高。
總結(jié) ??
整個(gè)面試過程結(jié)束,你與面試官展開了深入的討論,逐步展示了如何用 JavaScript 操作數(shù)組,從最簡單的查找最大值到復(fù)雜的數(shù)對(duì)查找,涵蓋了去重、排序、旋轉(zhuǎn)等經(jīng)典操作。你展示了每種方法的優(yōu)缺點(diǎn)和適用場景,讓面試官看到你不僅掌握了基礎(chǔ)的技術(shù),還能夠針對(duì)不同場景靈活選用最優(yōu)解。
面試官露出欣賞的微笑,對(duì)你的細(xì)致解答表示了充分的肯定。這場面試不僅展示了你的 JavaScript 基礎(chǔ)功底,更展現(xiàn)了你在實(shí)際開發(fā)中解決問題的敏捷思維。你從面試室中走出來,心里對(duì)自己這次表現(xiàn)感到滿意?;叵肫饎偛拍切┛碱},你知道,自己在面試中的思路與深度,已經(jīng)給面試官留下了深刻的印象。
你微微一笑,準(zhǔn)備迎接下一個(gè)挑戰(zhàn)。