又到了每一年的金三銀四招聘旺季,有幸得到了微軟的筆試機會,程序猿們應該都知道,老美的公司都喜歡懟數據結構與算法,微軟確定也不例外,我的以爲考數據結構對每個應聘者都公平,我此次投的是微軟蘇研院,筆試考察的不難,是最最多見的數據結構算法裸題,這裏記錄一下,也給出解法。前端
快排應該是最網紅的題了,從校招到社招,從後端到前端再到移動端,都會問,可是估計能手撕出來的不超過一半,能講清楚思路的估計不超過一半的一半,其實用兩個詞歸納,就是雙指針+遞歸分治,在每一輪遞歸的時候找到每一個基準數排完序後的位置,將小於這個基準數的全部數放到它的左邊,將大於這個基準數的全部數放到它的右邊,而後再分別遞歸它左邊的數組與它右邊的數組。好比說數組[2,3,1,5,6,4]:算法
初始狀態是這樣,我如今給兩個指針出來,一個指針指向頭,即arr[0] = 2, 一個指針指向尾,及arr[5] = 4,規定一個基準數,這裏直接用第一個數(arr[0] = 2)便可。開始第一次的遞歸處理,尾指針先從右往左掃,掃到第一個小於(注意是小於,而不是小於等於哦)基準數的位置停住,這時候頭指針再從左往右掃,掃到第一個大於基準數的位置停住,這時候是下面的圖示狀態: 交換兩個指針所指的數,成爲了下面的狀態: 兩個數交換完畢,右指針此時指的是arr[2] = 3, 左指針指着arr[1] = 1;交換完畢後右指針繼續從當前位置往左掃,掃到1的時候發現和左指針相遇了,那麼這個時候就結束左右指針的掃描,左右指針同時指着arr[1] = 1,即: 此時退出循環掃描的過程,交換基準數與左右指針同時所指的數的位置,開頭說了,基準數我選擇的是arr[0] = 2, 指針指的是arr[1] = 1; 交換事後就變成了: 這時候就發現基準數已經出如今了它排完序後應該在的位置(排完序後是[1,2,3,4,5,6],2出如今了第2位),比這個基準數小的數組出如今了它的左邊([1]出如今了2的左邊),比基準數大的出如今了它的右邊([3,5,6,4]出如今了2的右邊)。以後的過程就是對左右數組的分別遞歸處理。附上代碼: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),(又:二叉搜索樹,二叉排序樹)它或者是一棵空樹,或者是具備下列性質的二叉樹: 若它的左子樹不空,則左子樹上全部結點的值均小於它的根結點的值; 若它的右子樹不空,則右子樹上全部結點的值均大於它的根結點的值; 它的左、右子樹也分別爲二叉排序樹.bash
因此要是問你怎麼建立一顆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;
}
複製代碼
我相信不少人都能寫出二叉樹的遞歸遍歷:遞歸遍歷左子樹,輸出根節點,遞歸遍歷右子樹,三行代碼,完事,可是要問到非遞歸遍歷,估計大多數人就傻眼了,可是人家就要考你不會的啊,非遞歸遍歷其實就是藉助棧來完成:ui
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;
};
複製代碼
老美的公司,算法關必須過啊。因此,路漫漫其修遠兮,刷題刷題多刷題吧this