第一題是按序輸出格雷碼。輸入的參數是格雷碼長度N。python
剛上來可能緊張,沒什麼思路。面試官問了我一下,就提示我是否是能夠從前一個序列中找到規律。我一會兒反應過來,就跟他說了個人想法。ios
通常在交流後若是以爲你的思路沒問題,就開始在白板上寫代碼。要求是能運行的代碼。git
第二題是最長遞增子序列。Longest Increasing Subsequence - LeetCode
我首先想到動態規劃方法,就跟面試官說了一下。他說能夠的,你想一下方程吧。
想好後和他交流了一下,此次沒讓我寫代碼,但讓我繼續優化。不過此次始終沒想起來。
面試
第一題: 格雷碼算法
第二題:最長遞增子序列 (動態規劃O(n^2), 二分優化到O(nlogn)數組
也就幾分鐘以後開始作題。此次題目是求二叉樹中任意兩點造成的路徑上節點(每一個節點有個值)之和的最大值。(Leetcode 124)
我想到方法後也是先跟他確認,而後開始寫代碼。寫的時候我還問他節點值是否可能爲負。
寫好代碼以後他會仔細看代碼。(一面面試官也很仔細)幾乎是一行一行地讀。
此次讀代碼解釋代碼的時間比較久。就沒有第二題。
編輯器
三面應該是個Leader?也是先聊天,還說以前去南大宣講我記不記得他。哈哈,我說你這麼一說我纔想起來。
他就空着手過來,不像一二面面試官(順帶一提,二面面試官用的 MacBook + macOS)。
就閒聊了幾句,我就記得問我以爲本身的優點是什麼。而後問了前兩面問了啥題,而後開始作題。
此次這個題目羅裏吧嗦的:
有三個轉盤(A-Z),處於某一個狀態start,好比MSF。求出將start轉到另外一個狀態target所要轉動轉盤而造成的字符串序列。好比MSF->OFC:[MSF,NSF,OSF,OSE,...,OFC
。此外,有另外一個參數BlockList,是個字符串列表,輸出的序列不能包含BlockList中的字符串,即轉動時不能通過這些狀態。
問我有沒有問題他就出去了,我就開始寫,我就組合了一個BFS和遞歸寫了一個,有點亂,白板上也很差改。沒過多久他就回來了。開始也像前兩面同樣逐行讀代碼,解釋。我也不知道對不對🤦♂️。看他的表情也不知道對不對。
不過此次由於快到下班時間了,就很快結束了。
函數
一面
第一個題是「Z字形打印二叉樹」,給定一顆樹,先打印根節點,從第二行開始先從左到右,再從右到左打印。第一次面試真的有點緊張,剛開始敲鍵盤的時候手都在抖。這個題實際上是《劍指offer》上比較經典的題目了,還好我以前刷了一遍。因此在草稿紙上簡單畫了一下,就思路就比較清晰,給定兩個棧,分別交替存儲每層的節點。給面試講了一下大體思路以後,就開始寫代碼了,爲避免沉默的尷尬,一邊寫一邊給面試官講具體的思路。具體的代碼能夠參考牛客網-劍指offer-z字形打印二叉樹,這裏就不寫了。測試
作完以後面試官讓我計算一下複雜度,由於每一個元素分別入棧和出棧一次,時間複雜度是O(N)。棧裏存儲的元素也不會超過N,因此空間複雜度也是O(N)。複雜度的計算感受要求不是很嚴格,給出答案後面試官就沒說什麼,而後繼續下一題。優化
BFS遍歷題目
第二題,圖相關,找到最大的好友圈。給定N個club,每一個club裏有人員的ID,找出其中最大的好友圈。什麼算好友圈呢, 舉個例子比較容易理解:
有3個club,其中每一個club擁有的會員以下:
clubI: [1, 2, 3]
clubII: [2, 3, 4]
clubIII: [5, 6, 7]
由於2和3都屬於club1和club2,因此1,2,3,4都屬於同一個圈子。最大的好友圈數量就是4。
看到這個題的第一反應是深度優先遍歷(DFS),要作DFS的話,確定得用字典,每一個key對應一個list,而後遍歷就行了。可是怎麼設計key和list,還沒想好。由於不想讓面試陷入太長的尷尬期,就決定開始寫。最初的想法是以人員ID做爲key,club做爲list,遍歷每一個人擁有的club id,再根據該id遍歷該club下的人數,累加起來。但後來發現這種思路的複雜度過高,寫起來也比較麻煩,大概寫到一半後,面試以爲這樣複雜度過高了,讓我先停一下,讓我算算這樣作的複雜度,我估計了一下,沒想好,反正就是很高。面試官讓我再換個思路,想個簡單一點的,我忽然腦洞一開,以爲,我把他們每一個club當個集合,求下並集和交集不就好了嗎?若是兩個集合有交集,那就合併,沒有交集就不合並,代碼很簡潔,感受幾行就能寫完。忽然爲本身的腦洞鼓掌....可是面試官又問,這樣作的時間複雜度呢?最差的狀況每兩兩集合作交集,這一步複雜度爲O(N^2),再求並集,至少O(N^3)。O(N^3)實在過高了,面試官又讓我想一想簡單一點的,可是時間快到了,而後面試官就直接開始指引我了,把每一個人的ID看成圖的節點,用領接表來表示從一個點到另外一個點可達,已經遍歷了的點就標記一下,直到全部的點都被標記。面試官最後讓我說這個算法的複雜度,我算了算,O(N),確實好多了,代碼也不用寫了。
最後再問了問面試官部門的業務,而後就結束了。從頭至尾面試官都挺和善的,感受很不錯。
應該是並查集題目:
二面
一面和二面是沒有關係的,反正就是換我的來作題。其實個人二面應該是一面,但由於第一天把他放鴿子了,因此HR在次日從新安排了面試。
感受比上一個面試官要嚴肅一點,一來就直接作題,還說,「咱們搞快點,儘可能在45分鐘內結束。」(HR定的是一個小時)。第一個徹底沒見過,叫格雷碼(Gray Code,後來發現leetcode上有原題),傳入一個N,要求返回第N行的格雷碼。格雷碼是這樣的:
2: 00 01 11 10
3: 000 001 011 010 110 111 101 100
4: 0000 0001 0011 0010 0110 0111 0101 0100 1100 1101 1111 1110 1010 1011 1001 1000
他和二進制很相像,可是每次只變化一位。
徹底沒見過這種題(刷的題比較少),真的有點緊張,一開始想從二進制入手,但想了想沒思路,因而就想單純的找規律。看了一會,終於看出規律來了,好比3是由在2的格雷碼前面先加個0,再把2反轉一下加個1,提煉出來就是G(N + 1) = (0 + G(N)) +(1 + R(G(N)),R表示反轉列表。發現規律後就很好寫代碼了。爲了方便,這題直接用python。
first = ["00", "01", "11", "10"] dp = {} dp[2] = first def grayCode(n): if n in dp: return dp[n] else: temp = list(map(lambda x: "0" + x, grayCode(n - 1))) + list(map(lambda x: "1" + x, grayCode(n - 1).reverse())) dp[n] = temp return dp[n]
以後照例面試官讓我講一下複雜度,若是以N表示位數的話,時間複雜度就是O(N * 2 ^ N),由於反轉字符串須要花費2^N,空間複雜度是O(2^N)。這個時間複雜度挺嚇人的,可是面試官也沒說啥,就繼續下一個問題。
因爲時間問題,第二個問題面試官沒有讓我寫代碼了,只是說下思路和計算複雜度就行。問題是,給定一個整數數組,求子數組的數量,要求子數組的元素個數大於等於2,且順序不能變。好比[1,2,3,4,5], [1, 2]或[1,3]是他的子數組,可是[2,1]不是。因此不能是簡單的排列組合。
個人思路是等差數列的求和,
好比個數爲2的時候,計算公式: F(2) = (n - 1) + (n - 2) + (n - 3) + ... +2 + 1 = (n / 2) * (n - 1)
個數爲3的時候, 遞歸,取出第一個元素後,對剩下的子數組又重複上面的計算。
這裏感受不是很嚴謹,尚未仔細驗證,面試官就開始問下一個問題,求全部子數組中的遞增子數組中長度最長的數組。
這裏想了好久,沒有想好,由於面試官先讓我算子數組的個數,我潛意識裏就覺得是已經獲得了全部子數組,要比較他們的長度和是否遞增。最終仍是沒有想到解決方案,面試官說沒事,面試就這樣吧,語氣也很友好。到面試快結束的時候才反應過來,其實不必管全部子數組,只須要在原數組中查找最長的遞增子數組就行了,可是具體怎麼作也沒思路,而後面試就結束了。
後來在leetcode上查了一下,有一個用動態規劃的o(N^2)的解法,有個只須要O(NlogN)的解法要用到線段樹,就直接放棄了,這裏只貼下DP的解法吧:
class Solution(object): def findNumberOfLIS(self, nums): N = len(nums) if N <= 1: return N lengths = [0] * N #lengths[i] = longest ending in nums[i] counts = [1] * N #count[i] = number of longest ending in nums[i] for j, num in enumerate(nums): for i in xrange(j): if nums[i] < nums[j]: if lengths[i] >= lengths[j]: lengths[j] = 1 + lengths[i] counts[j] = counts[i] elif lengths[i] + 1 == lengths[j]: counts[j] += counts[i] longest = max(lengths) return sum(c for i, c in enumerate(counts) if lengths[i] == longest)
三面
一二面結束以後就收到了三面的邀請,過了一天就開始三面。網上查的狀況大可能是三面只作一個題,結果我仍是作了兩個題。由於終面,面試官是個Leader,感受獲得他頗有水平。一開始有個英文的自我介紹,由於有了一面時自我介紹的慘痛教訓,因此這裏稍微準備了一下,說得比較流利,結果面試官立刻就開始英文問問題,聊聊爲何喜歡微軟啊,還有項目啥的。沒多久我就表示不行了,能不能說中文,他說OK,而後就切換到中文。
而後開始作題,和前兩次在線編輯不同的是,這一次作題讓我打開本地的編輯器,他經過遠程桌面看我作題。他問我平時用什麼語言,我說C++和Python,他就讓我用C++,因而我就打開了VSCode。
第一個題目是,寫一個函數,驗證輸入的字符串是不是IPv4。IPv4的要求是有4段,每一段的數字在區間[0,255]內。這個題是蠻簡單的,可是他要求我不能用任何STL的函數,string都不行,連字符串轉int的方式也要本身寫。可是寫完以後還讓我舉出須要用到的測試用例,在不斷舉例的過程當中,發現本身代碼裏存在着好多bug,最終改了很久,終於改完了。
bool judgeIPV4(char* s) { if (!s) return false; int digit = -1; count = 0; while (*s != '\0') { if (*s >= '0' && *s <= '9' && digit == -1) { digit = 0; } if (*s >= '0' && *s <= '9' && digit != -1) { int temp = *s - '0'; digit = digit * 10 + temp; if (digit > 255) { return false; } } else if(digit == '.') { if (digit < 0) { return false; } count += 1; if (count > 3) return false; digit = -1; } else { return false; } s++; } if (count != 3 || digit < 0) return false; return true; }
這個題從算法上來講比較簡單,可是須要考慮的狀況不少,好屢次我說我以爲沒問題了,他仍是讓我再看看,果真仍是有bug。。。最後一個bug是超過int範圍了的問題。雖然磕磕碰碰了好久,可是最終仍是完成了,又開始下一題。
我剛聽到下一題的時候我心裏是崩潰的,不是說好的三面只面一個題嗎???結果還好,第二題是我見過的,真的是運氣好。題目是給定前序遍歷和中序遍歷,重建二叉樹。這個題的核心是知道前序遍歷的第一個節點是root,中序遍歷中在root以前的節點屬於左子樹,root以後的屬於右子樹。
#include<iostream> #include<vector> using namespace std; struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode(int x): val(x), left(NULL), right(NULL) {} }; TreeNode *rebuiltTree(vector<int> pre, vector<int> mid) { if (pre.size() == 0) return NULL; TreeNode *root = new TreeNode(pre[0]); vector<int> left_pre, right_pre, left_mid, right_mid; bool flag = false; for (int i = 0; i < mid.size(); i++) { if(pre[0] == mid[i]) { flag = true; continue; } if(!flag) { left_pre.push_back(pre[i + 1]); left_mid.push_back(mid[i]); } else { right_pre.push_back(pre[i]); right_mid.push_back(mid[i]); } } root->left = rebuiltTree(left_pre, left_mid); root->right = rebuiltTree(right_pre, right_mid); return root; }
寫完以後,他讓我想一想這個代碼裏存在的bug。我舉了三種,首先是若是節點值超過了int的範圍,第二是遞歸中佔用的內存超過 了堆的限制,第三是若是有重複的元素。。。他問我有重複的元素咋辦,我說那就沒有辦法重建了啊,他笑了笑說就這樣吧,這也是一個待驗證的問題。
面試結束後不久就收到了hr電話,經過了