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