位元組跳動(今日頭條)推薦演算法實習生面試

Microstrong0305發表於2018-05-16


2018-05-16 17:00 一面:

(1)自我介紹。

(2)介紹自己是如何去除水印和增加水印安全性的工作,對於自己做過的專案問的很具體。

(3)讓詳細介紹一下邏輯迴歸,包括邏輯迴歸的分類公式,損失函式、邏輯迴歸分類的過程。

(4)問了一下邏輯迴歸中損失函式的作用?

損失函式是評價模型的一個標準,它是衡量模型的預測值和真實值之間的誤差的一種評價標準。

(5)邏輯迴歸中除了損失函式能衡量模型的好壞,還有沒有其他的方法?

哎。。。自己悟性太低啦!問到這的時候,完全不知道面試官要問啥。現在想想應該是要問精度、錯誤率、準確率、召回率、ROC曲線和AUC面積等衡量模型的一些標準指標。

然後,這個問題面試官就說先過去吧!接著下一道。

(6)接下來,重點來了!位元組跳動中傳說的手撕程式碼來了!

面試官問:對資料結構和演算法有沒有了解啊!然後直接就給了一道演算法題,先說思路,然後就是現場寫程式碼。


題目:長度為n的陣列中,總是存在一個斷點(下標記為i),陣列中斷點前面的數字是有序的,斷點後的數字也是有序的,且斷點後邊的數字總是小於前面的數字。如果直接把斷點後邊的數字移動到陣列的前邊,那麼這個陣列將是有序的,具體描述如下所示。求這個陣列中的第n/2大的數。

原陣列:
6,8,10,13,1,2,4
找到斷點移動之後的陣列:
1,2,4,6,8,10
#############################
原陣列:
5,1,2,3,4,
找到斷點移動之後的陣列:
1,2,3,4,5
##############################
原陣列:
2,3,4,5,1
找到斷點移動之後的陣列:
1,2,3,4,5

我的思路:先找到斷點的下標i,然後根據下標直接取出第n/2(向上取整)大的元素。


1.如果你的第n/2大的數在斷點後邊,那麼可以直接通過下標計算得出第n/2大的數的下標。下標計算公式如下:


2.如果你的第n/2大的數在斷點的前面,那麼你可以把斷點後邊小於第n/2大的數給算上,然後在往前面查詢到第n/2大的數。下標計算公式如下:


public class Main {
	
	public static void main(String[] args){
//	    int[] array = {6, 8, 10, 13 , 1, 2, 4};
//		int[] array = {5, 1, 2, 3, 4};
		int[] array = {2, 3, 4, 5, 1};
	    int n = array.length;
	    int location = (int) Math.ceil(n/2.0);
	    int index = searchIndex(array);
	    int temp = 0;
	    if(location <= n - index){
	        temp = array[index+location - 1];
	    }else{
	        temp = array[location-(n-index+1)];
	    }
	    System.out.print(temp);
	}
	
	public static int searchIndex(int[] array){
	    for(int i=0; i<array.length; i++){
	        if(array[i] > array[i+1]){
	            return i + 1;
	        }
	    }
	    return 0;
	}
	    
}	

時間複雜度是O(n),空間複雜度是0。

這個演算法時間複雜度是O(n),主要是在於查詢斷點的下標i時花費了時間。面試官讓我來改進查詢下標i的演算法。我當時直接想出的是折半查詢,面試官肯定了是折半查詢演算法。但是在思考用折半查詢的時候,我自己遇到了兩個細節問題,沒有回答出來,所以這道題用折半查詢沒有回答出來。

遇到了兩個細節問題是:

(1)我們要找陣列中最小數的下標,那麼我們前提是不知道最小數是多少,如何進行比較查詢最小數。

(2)在折半查詢的過程中,如何確定最小數是在左半邊還是在右半邊,換句話說,你是搜尋左邊的陣列還是搜尋右邊的陣列呢!

給出程式碼:

public class Main {
	
	public static void main(String[] args){
	    int[] array = {6, 8, 10, 13 , 1, 2, 4};
//		int[] array = {5, 1, 2, 3, 4};
//		int[] array = {2, 3, 4, 5, 1};
	    int n = array.length;
	    int location = (int) Math.ceil(n/2.0);
	    int index = Select_k(array, 0, n-1, location);
	    System.out.print(index);
	}
	
	 public static int quickSortOneTime(int[] array, int low, int high){ //一趟快速排序   
		 int  key = array[low];  
         while(low < high){  
        	while(key < array[high] && low < high)  high--;
            array[low] = array[high];  
            while(key > array[low] && low < high)   low++;  
            array[high] = array[low];
         }  
	    array[high] = key;  
	    return high;
	    }  
	 
	 public static int Select_k(int[] array, int low, int high, int k) {
		 int index;
		 if(low == high) return array[low];
		 int partition = quickSortOneTime(array, low, high);
		 index = high - partition + 1;  //找到的是第幾個大值
		 if(index == k) {
			 return array[partition];
		 }else if(index < k) {//此時向左查詢
			 return Select_k(array, low, partition-1, k-index);  //查詢的是相對位置的值,k在左段中的下標為k-index
		 }else {
			 return Select_k(array, partition+1, high, k);
		 }
	 }
	    
}	

時間複雜度數O(logN)

詳細介紹看我的這篇文章:

演算法-在有序陣列、無序陣列中進行折半查詢和二分法找無序陣列中的第k小(大)的數

地址:https://blog.csdn.net/program_developer/article/details/80348077

相關文章