新鮮出爐的頭條面試演算法
昨天下午實驗室有一個同學參加了今日頭條的面試,面試最終是以一個演算法題結束。
題目如下:
給你一個有序整數陣列,陣列中的數可以是正數、負數、零,請實現一個函式,這個函式返回一個整數:返回這個陣列所有數的平方值中有多少種不同的取值。舉例:
-
nums = {-1,1,1,1},
那麼你應該返回的是:1。因為這個陣列所有數的平方取值都是1,只有一種取值
-
nums = {-1,0,1,2,3}
你應該返回4,因為nums陣列所有元素的平方值一共4種取值:1,0,4,9
在往下看之前,請先進行思考,如果當時是你在面試,你會給出什麼樣的結題思路?下面會給出兩種解法,最優解:時間複雜度:O(n)、空間複雜度O(1)。無論有沒有思路,在往下看之前一定要有自己的思考
第一種也是最為直接、簡單的思路:把nums陣列中所有數的絕對值,全部計算完之後再統計有多少種不同的取值。
實現程式碼如下:
public int handle(int[] nums) { if(nums==null || nums.length==0) return 0; HashSet<Integer> set = new HashSet<Integer>(); for (int number : nums) set.add(Math.abs(number)); return set.size(); }
上面的實現也很簡單,主要是利用HashSet的去重特性,最後直接返回set的size。
但是呢,僅僅給出這種解法是過不了面試的,昨天面試的同學在面試結束之後才想到更優的解法,所以....當然這個同學已經拿到了很好的offer—網易。舉這個案例只想和學弟學妹們在強調一遍:演算法的重要性。
上面直接使用set的解法沒有利用題目中有序條件,這也是優化的方向。
那如何利用好有序這個條件呢?
解思路法如下:
絕對值相等可能有哪些情況呢?
-
兩個同符號數的絕對值相等,這也意味著在有序陣列中這個兩個數是相鄰的,這時只需要移動指標跳過相鄰相等的數即可。
-
兩個異符號數的絕對值相等,所以我們需要維護兩個指標,一個指標從前往後移動,一個從後往前移。原因是前面的負數絕對值可能與後面整數的絕對值相等,我們需要比較前後兩個指標絕對值的大小。
綜上,我們需要維護兩個指標,i開始指向陣列第一個元素,i=0;j開始指向陣列最後一個元素,j = nums.length-1。i,j指標的另外含義是:陣列中索引小於i和大於j的元素都已經被處理了;i,j指向的是未處理元素中絕對值最大的兩個元素。當i>j的時候表明所有的元素都已經被處理了,迴圈結束。
那麼如何移動指標呢?
-
如果nums[i]與nums[j]的絕對值相等,此時執行i++,直到nums[i]的絕對值不等於nums[j]的絕對值(跳過相鄰重複元素);j也是做類似的移動,只不過j是向前移,j--;最後計數器加1。
-
如果nums[i]的絕對值大於nums[j]的絕對值,我們移動指標i,並且計數器加1。原因?因為i和j指向未處理元素中絕對值最大的那個,nums[i]的絕對值已經是未處理元素中絕對值最大的兩個數,也就是不可能存在一個未被處理的元素,它的絕對值與nums[i]的絕對值相等。所以這種情況下我們移動i指標。注意這裡所說的移動指的是:執行i++直到nums[i]的絕對值發生了改變(跳過相鄰相等的元素)。
-
如果nums[j]的絕對值大,那麼與上面類似,移動j指標。
具體程式碼實現如下:
public int handle (int[] nums) {
if(nums==null || nums.length==0)
return 0;
// result的縮寫,最後的返回值
int res = 0;
//i是前指標;j是後指標
int i = 0;
int j = nums.length - 1;
while (i <= j) {
int num1=Math.abs(nums[i]);
int num2=Math.abs(nums[j]);
if (num1 > num2) {//移動i
// 這兩個數的絕對值不相等
res += 1;
while(i<=j && Math.abs(nums[i])==num1)
//過濾掉相鄰的絕對值相等的數
i++;
} else if (num1 < num2) {
// 這兩個數的絕對值不相等
res += 1;
while(i<=j && Math.abs(nums[j])==num2)
//過濾掉相鄰的絕對值相等的數
j--;
} else {
res += 1;
while(i<=j && Math.abs(nums[i])==num1)//去重
i++;
while(i<=j && Math.abs(nums[j])==num2)//去重
j--;
}
}
return res;
}
對本題有疑問的同學,歡迎在評論區留言探討~
總結:
面試中最常考的演算法題主要是:陣列、二叉樹。期中呢,HashMap、HashSet等輔助資料結構使用比較多,“雙指標法”在有序陣列相關演算法題中使用較多;無序陣列,使用HashMap和HashSet較多;二叉樹大多使用遞迴、dfs來解題。
另外,在實際面試中,演算法也是這樣一步步優化:最先提出的方案沒有那麼“優”也沒有關係,如果面試官不滿意,繼續在此基礎上進行優化,大多時候面試官會提示優化的方向。當然能直接給出優化方案最好~
公眾號後臺回覆“資料”即可獲得2T的學習資料(長期更新ing)以及博主整理好的精品資料一份。2T資料涵蓋各個求職方向,並且每一個方向都有對應的經典專案,可寫入簡歷的大型專案。