上一篇文章能受到這樣的關注度,感謝各位同學的點贊和評論,給了我很多動力繼續去更新這個系列,也希望它們能夠對大家有一定的幫助。蟹蟹大家。
傳送門
- 面試總結(1):HTML佈局、CSS選擇器及JS基礎綜合能力知識點
- 演算法基礎:陣列flat、去重及排序
- react vue 理解及基礎知識
- 跨域問題解決方案
- http協議狀態碼
- 快取及更新問題
- webview與原生應用互動
- 伺服器端知識
演算法基礎:陣列 flat 、去重及排序
廢話不多說,直接上題。
let arr = [
[
['1-7', '2-6'],
'4-6',
[
['2-0', '1-4'],
['3-9'],
'4-5',
],
]
]
// Q1: 完成陣列 flat 函式
function flat(arr) {
// code
return arr
}
arr = flat(arr);
console.log(arr);
// Q2: 計算 arr 中所有的值:'1-7' => 1 * 7 = 7, 返回一個數字組成的陣列
function calc(arr) {
// code
return arr;
}
arr = calc(arr);
console.log(arr);
// Q3: 對這個陣列排序和去重
function sortAndReduce(arr) {
// code
return arr;
}
arr = sortAndReduce(arr);
console.log(arr);
複製程式碼
Q1: 陣列 Flat
時間回溯
這個陣列結構比較深,這應該是整個題目的考點所在。看這個樣子應該是需要用遞迴,不!應該還有更好的方法,?那就使用ES 2019 的 Array.prototype.flat 函式吧!然後被面試官一票否決。在塗塗改改和思考的時間中,面試官問了我的思路結束了這個問題。
方案1: 遞迴
如果有對遞迴不太熟悉的同學,可以看看我的讀書筆記【演算法圖解】讀書筆記:第3章 遞迴。
遞迴的核心就在於兩步:找到基線條件和遞迴條件。
function flat(arr) {
const result = []; // 利用閉包快取我們的結果
function _flat(arr) {
arr.forEach(element => {
if(Array.isArray(element)) { // 遞迴條件
_flat(element);
} else { // 基準條件
result.push(element); // 將符合結果的值推入我們的結果陣列中
}
})
}
_flat(arr);
arr = result;
return arr;
}
// 更加簡練的版本
// 感謝 @zwlafk
const flat = arr => [].concat(...arr.map(v => Array.isArray(v) ? flat(v) : v));
複製程式碼
方案2: 迭代 - 廣度優先搜尋
這個思路是我借鑑《圖解演算法》中廣度優先搜尋演算法章節寫的。
- 建立一個陣列,儲存結果
- 建立一個佇列
- 初始化
- 使用 while 迴圈去遍歷 list 裡面的每一項
- 將第一項推出佇列
- 如果是陣列,將子項依次推入佇列
- 如果是字串,將子項推入結果
- 當 list 長度為0時候,遍歷完成
但是廣度優先搜尋的結果是不保證順序的。
- 參考書籍:《圖解演算法》
- 不推薦的筆記,沒書可以看看【演算法圖解】讀書筆記:第6章 廣度優先搜尋
function flat(arr) {
const result = []; // 儲存結果
const list = []; // 佇列
function _forEach(arr) {
arr.forEach(el => {
if(Array.isArray(el)) list.push(el); // item 如果是陣列,將子項依次推入佇列
else result.push(el); // item 如果是字串,將子項推入結果
});
}
_forEach(arr); // 初始化
while(list.length > 0) { // 當 list 長度為0時候,遍歷完成
const item = list.shift();
_forEach(item);
}
arr = result;
return arr;
}
複製程式碼
TODO:
- 上面兩個方法只是我的拙見,希望可以在評論區看見更好更優秀的演算法
方案3: 投機取巧的 toString 們
感謝 @IWANABETHATGUY 同學的賜教。
// 首頁你得確定你的資料裡面沒有字串 ',' 哦
function flat(arr) {
arr = arr.toString().split(',')
return arr;
}
// or
// 異曲同工
function flat(arr) {
arr = arr.join(',').split(',')
return arr;
}
複製程式碼
方案4: 迭代 - 深度優先搜尋
感謝 @IWANABETHATGUY 同學的賜教。
原理與廣度優先搜尋類似,通過模擬棧的行為去遍歷陣列。好處是能夠保證有序輸出。
function flat(arr) {
let result = [];
let stack = []; // 模擬棧的行為
function forEachRight(arr) {
for (let i = arr.length - 1; i >= 0; i--) { // 先進後出
const item = arr[i];
if(Array.isArray(item)) stack.push(item);
else result.push(item);
}
}
if (arr.length > 0) forEachRight(arr);
while (stack.length > 0) { // 當棧空了,遍歷完成
let current = s.pop();
if(current.length > 0) {
forEachRight(current); // 感謝 @Drowned-fish 朋友的建議
}
}
return ret;
}
複製程式碼
Q2: 陣列計算 '1-7' => 1 * 7 = 7
這個問題難度不大,就是考察一些常用方法的使用,直接上程式碼。
function calc(arr) {
// 隨手騷一下,不建議 eval
arr = arr.map(el => eval(el.replace('-', '*')));
return arr;
}
// or
function calc(arr) {
arr = arr.map(el => {
const [n1, n2] = el.split('-');
return +n1 * +n2;
});
return arr;
}
複製程式碼
Q3: 陣列排序和去重
陣列去重可以通過 ES6 的 Set 完成。傳送門:ES6 Set 資料結構,不作贅述。陣列排序可以使用 Array.prototype.sort 函式實現。但是顯然考察演算法內容,不能直接使用原生方法,而且排序和去重同時完成,效能肯定更好。
我之前寫過一篇常規的幾種排序方法的對比和實現,【JS面試向】選擇排序、桶排序、氣泡排序和快速排序簡介,這裡我直接使用快速排序完成排序和去重工作。
function sortAndReduce(arr) {
if(arr.length < 2) {
return arr;
} else {
const pivot = arr[0]; // 基準值
const lowArr= []; // 小的放左邊
const hightArr = []; // 大的放右邊
arr.forEach(current => {
if(current > pivot) hightArr.push(current);
else if(current < pivot) lowArr.push(current);
})
return sortAndReduce(lowArr).concat(pivot, sortAndReduce(hightArr));
}
}
複製程式碼
總結:
- 書上得來終覺淺。學會到成功其實還有很長的距離。這次面試就讓我知道了緊張的原因來自於基礎不紮實。
- 不說了,去刷 leetcode 了。