又到了每年的金三銀四招聘旺季,有幸獲得了微軟的筆試機會,程式猿們應該都知道,老美的公司都喜歡懟資料結構與演算法,微軟肯定也不例外,個人覺得考資料結構對每一個應聘者都公平,我這次投的是微軟蘇研院,筆試考察的不難,是最最常見的資料結構演算法裸題,這裡記錄一下,也給出解法。
1 快速排序
快排應該是最網紅的題了,從校招到社招,從後端到前端再到移動端,都會問,但是估計能手撕出來的不超過一半,能講清楚思路的估計不超過一半的一半,其實用兩個詞概括,就是雙指標+遞迴分治,在每一輪遞迴的時候找到每個基準數排完序後的位置,將小於這個基準數的所有數放到它的左邊,將大於這個基準數的所有數放到它的右邊,然後再分別遞迴它左邊的陣列與它右邊的陣列。比如說陣列[2,3,1,5,6,4]:
![微軟前端社招筆試詳解](https://i.iter01.com/images/b41587f05dde2a12e770858ce22e5806c1e4ea36fc94ee5652f0bf9d069ff627.png)
![微軟前端社招筆試詳解](https://i.iter01.com/images/d8db65d33ea5eff04295b667f53fb4b5e70338d0542a8caf660af278cdf43492.png)
![微軟前端社招筆試詳解](https://i.iter01.com/images/3d4279b3db109364f7fdf6a11eb0fc2ec335d41a212a856f9c6d3fbca89e8686.png)
![微軟前端社招筆試詳解](https://i.iter01.com/images/15abb148fd1ef37c89468aa82a11209c3ab74864ac5fee180edd1849dec986e6.png)
![微軟前端社招筆試詳解](https://i.iter01.com/images/ae9addff2850006706c364e0ccdb49ebada31544fd7ac74e2661475ef6d1b28c.png)
function quickSort(arr, begin, end) {
//遞迴出口
if(begin >= end)
return;
var l = begin; // 左指標
var r = end; //右指標
var temp = arr[begin]; //基準數,這裡取陣列第一個數
//左右指標相遇的時候退出掃描迴圈
while(l < r) {
//右指標從右向左掃描,碰到第一個小於基準數的時候停住
while(l < r && arr[r] >= temp)
r --;
//左指標從左向右掃描,碰到第一個大於基準數的時候停住
while(l < r && arr[l] <= temp)
l ++;
//交換左右指標所停位置的數
[arr[l], arr[r]] = [arr[r], arr[l]];
}
//最後交換基準數與指標相遇位置的數
[arr[begin], arr[l]] = [arr[l], arr[begin]];
//遞迴處理左右陣列
quickSort(arr, begin, l - 1);
quickSort(arr, l + 1, end);
}
var arr = [2,3,4,1,5,6]
quickSort(arr, 0, 5);
console.log(arr)
複製程式碼
思考:為什麼是右指標先掃而不是左指標先掃呢,大家自己想想吧哈哈,模擬一下就知道了。
發散性思考
上文中我提到了左陣列,右陣列,還提到了基準數的概念,其中,左陣列中的所有值都小於基準數,右陣列中的所有值都大於基準數,而且快排還是個遞迴的過程。我這裡如果做一下類比,如果我把基準數看成是樹根,把左陣列看成是根的左孩子,右陣列看成是根的右孩子,相信學過資料結構的童鞋都知道了,那不就是一顆BST嗎。哈哈確實如此,其實你會發現BST的中序遍歷出來就是一個有序陣列,所以上文中快排的過程就是一個建立二叉搜尋樹的過程。
二叉查詢樹(Binary Search Tree),(又:二叉搜尋樹,二叉排序樹)它或者是一棵空樹,或者是具有下列性質的二叉樹: 若它的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值; 若它的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值; 它的左、右子樹也分別為二叉排序樹.
所以要是問你怎麼建立一顆BST,想必也能信手拈來了吧,廢話不說上程式碼:
function vNode(value) {
this.val = value;
this.left = this.right = null;
}
function createBST(arr) {
var len = arr.length;
if(len < 1)
return;
var l = 0;
var r = len - 1;
var temp = arr[0];
while(l < r) {
while(l < r && arr[r] >= temp)
r --;
while(l < r && arr[l] <= temp)
l ++;
[arr[l], arr[r]] = [arr[r], arr[l]];
}
[arr[0], arr[l]] = [arr[l], arr[0]];
var root = new vNode(arr[l]);
root.left = createBST(arr.slice(0, l));
root.right = createBST(arr.slice(l + 1));
return root;
}
複製程式碼
二叉樹的非遞迴中序遍歷
我相信很多人都能寫出二叉樹的遞迴遍歷:遞迴遍歷左子樹,輸出根節點,遞迴遍歷右子樹,三行程式碼,完事,但是要問到非遞迴遍歷,估計大多數人就傻眼了,但是人家就要考你不會的啊,非遞迴遍歷其實就是藉助棧來完成:
var inorderTraversal = function(root) {
const res = [];
const stack = [];
while(root||stack.length !== 0)
{
while(root)
{
stack.push(root);
root=root.left;
}
if(stack.length)
{
let p=stack[stack.length - 1];
res.push(p.val);
stack.pop();
root = p.right;
}
}
return res;
};
複製程式碼
老美的公司,演算法關必須過啊。所以,路漫漫其修遠兮,刷題刷題多刷題吧