tft每日頭條

 > 職場

 > 算法思維的面試題目

算法思維的面試題目

職場 更新时间:2024-05-24 06:46:40

算法思維的面試題目(互聯網公司常見面試算法題)1

1、假設淘寶一天有5億條成交數據,求出銷量最高的100個商品并給出算法的時間複雜度。

先用哈希,統計每個商品的成交次數,然後再用在N個數中找出前K大個數的方法找出成交次數最多的前100個商品。

優化方法:可以把5億個數據分組存放,比如放在5000個文件中。這樣就可以分别在每個文件的10^6個數據中,用哈希 堆統計每個區域内前100個頻率最高的商品,最後求出所有記錄中出現頻率最高的前100個商品。

2、有10億個雜亂無章的數,怎樣最快地求出其中前1000大的數。

方法一:

建一個1000個數的最小堆,然後依次添加剩餘元素,如果大于堆頂的數(堆中最小的),将這個數替換堆頂,并調整結構使之仍然是一個最小堆,這樣,遍曆完後,堆中的1000個數就是所需的最大的1000個。算法的時間複雜度為O(nlogk)=n*log1000=10n(n為10億,k為1000)。

優化的方法:分治法。可以把所有10億個數據分組存放,比如分别放在1000個文件中。這樣處理就可以分别在每個文件的10^6個數據中找出最大的10000個數,合并到一起再找出最終的結果。

優化的方法:如果這10億個數裡面有很多重複的數,先通過Hash法,把這10億個數字去重複,這樣如果重複率很高的話,會減少很大的内存用量,從而縮小運算空間,然後通過分治法或最小堆法查找最大的1000個數。

方法二:

1.用每一個BIT标識一個整數的存在與否,這樣一個字節可以标識8個整數的存在與否,對于所有32位的整數,需要512Mb,所以開辟一個512Mb的字符數組A,初始全0

2.依次讀取每個數n,對于數n,n存放在A[N>>3]中的某個bit,因此,将A[n>>3]設置為A[n>>3]|(1<<(n%8))(這裡是1左移幾位),相當于将每個數的對應位設置為1

3.在A中,從數組尾開始向前遍曆,從大到小讀取1000個值為1的數,就是最大的1000個數了。

這樣讀文件就隻需要1遍,在不考慮内存開銷的情況下,應該是速度最快的方法了。

3、給一列無序數組,求出中位數并給出算法的時間複雜度。

若數組有奇數個元素,中位數是a[(n-1)/2];若數組有偶數個元素,中位數為a[n/2-1]和a[n/2]兩個數的平均值。這裡為方便起見,假設數組為奇數個元素。

思路一:把無序數組排好序,取出中間的元素。時間複雜度取決于排序算法,最快是快速排序,O(nlogn),或者是非比較的基數排序,時間為O(n),空間為O(n)。這明顯不是我們想要的。

思路二:采用快速排序的分治partition過程。任意挑一個元素,以該元素為支點,将數組分成兩部分,左邊是小于等于支點的,右邊是大于支點的。如果左側長度正好是(n-1)/2,那麼支點恰為中位數。如果左側長度<(n-1)/2, 那麼中位數在右側,反之,中位數在左側。 進入相應的一側繼續尋找中位數。

//快速排序的分治過程找無序數組的中位數 int partition(int a[], int low, int high) //快排的一次排序過程 { int q = a[low]; while (low < high) { while (low < high && a[high] >= q) high--; a[low] = a[high]; while (low < high && a[low] <= q) low ; a[high] = a[low]; } a[low] = q; return low; } int findMidium(int a[], int n) { int index = n / 2; int left = 0; int right = n - 1; int q = -1; while (index != q) { q = partition(a, left, right); if (q < index) left = q 1; else if (q>index) right = q - 1; } return a[index]; }

思路三:将數組的前(n 1)/2個元素建立一個最小堆。然後,對于下一個元素,和堆頂的元素比較,如果小于等于,丢棄之,如果大于,則用該元素取代堆頂,再調整堆,接着看下一個元素。重複這個步驟,直到數組為空。當數組都遍曆完了,(堆中元素為最大的(n 1)/2個元素,)堆頂的元素即是中位數。

//構建最小堆找無序數組的中位數 void nswap(int& i, int& j) { i = i^j; j = i^j; i = i^j; } void minHeapify(int a[], int i, int len) { int temp; int least = i; int l = i * 2 1; int r = i * 2 2; if (l < len && a[l] < a[least]) least = l; if (r < len && a[r] < a[least]) least = r; if (least != i) { nswap(a[i], a[least]); minHeapify(a, least, len); } } void buildMinHeap(int a[], int len) { for (int i = (len-2) / 2; i >= 0; i--) { minHeapify(a, i, len); } } int findMidium2(int a[], int n) { buildMinHeap(a, (n 1) / 2); for (int i = (n 1) / 2; i < n; i ) { if (a[i] > a[0]) { nswap(a[i], a[0]); minHeapify(a, 0,(n 1) / 2); } } return a[0]; }

引申一:查找N個元素中的第K個小的元素

編程珠玑給出了一個時間複雜度O(N)的解決方案。該方案改編自快速排序。經過快排的一次劃分, 1)如果左半部份的長度>K-1,那麼這個元素就肯定在左半部份了 2)如果左半部份的長度==K-1,那麼當前劃分元素就是結果了。 3)如果。。。。。。。<K-1,那麼這個元素就肯定在右半部分了。 并且,該方法可以用尾遞歸實現。效率更高。也可以用來查找N個元素中的前K個小的元素,前K個大的元素。。。。等等。

引申二:查找N個元素中的第K個小的元素,假設内存受限,僅能容下K/4個元素。分趟查找,第一趟,用堆方法查找最小的K/4個小的元素,同時記錄剩下的N-K/4個元素到外部文件。第二趟,用堆方法從第一趟篩選出的N-K/4個元素中查找K/4個小的元素,同時記錄剩下的N-K/2個元素到外部文件。。。。第四趟,用堆方法從第一趟篩選出的N-K/3個元素中查找K/4個小的元素,這是的第K/4小的元素即使所求。

4、輸入一個整型數組,求出子數組和的最大值,并給出算法的時間複雜度。

設b[i]表示a[0...i]的子數組和的最大值,且b[i]一定包含a[i],即:sum為子問題的最優解,

1. 包含a[i],即求b[i]的最大值,在計算b[i]時,可以考慮以下兩種情況,因為a[i]要求一定包含在内,所以

1) 當b[i-1]>0, b[i] = b[i-1] a[i]

2) 當b[i-1]<=0, b[i] = a[i], 當b[i-1]<=0,這時候以a[i]重新作為b[i]的起點。

2. 不包含a[i],即a[0]~a[i-1]的最大值(即0~i-1局部問題的最優解),設為sum

最後比較b[i]和 sum,即,如果b[i] >sum ,即b[i]為最優解,然後更新sum的值.

在實現時,bMax代表 b[k], sum更新前代表前一步子問題的最優解,更新後代表當前問題的最優解。實現如下:

//求數組的子數組和的最大值,時間複雜度為O(n) int maxSumArr(int a[], int n,int* start, int* end) { int s, e; int sum = a[0]; int bMax=a[0]; *start = *end = 0; for (int i = 1; i < n; i ) { if (bMax > 0) //情況一,子數組包含a[i],且b[i-1]>0(上一次的最優解大于0),b[i] = b[i-1] a[i] { bMax = a[i]; e = i; } else //情況二,子數組包含a[i],且b[i-1]<=0(上一次的最優解小于0),這時候以a[i]重新作為b[i]的起點。 { bMax = a[i]; s = i; e = i; } //情況三,子數組不包含a[i],即b[i]=sum if (bMax > sum) //三種情況相比較,最大值作為更新後的最優解,存在sum { sum = bMax; *start = s; *end = e; } } return sum; }

引申:求子數組和的最小值

同理。

//求數組的子數組和的最小值,時間複雜度為O(n) int minSumArr(int a[], int n, int* start, int* end) { int s, e; int bMin = a[0]; int sum = a[0]; *start = *end = 0; for (int i = 0; i < n; i ) { if (bMin < 0) //情況一,子數組包含a[i], 且b[i-1]<0,b[i] = b[i-1] a[i] { bMin = a[i]; e = i; } else //情況二,子數組包含a[i],且b[i-1] > 0,這時候以a[i]重新作為b[i]的起點 { bMin = a[i]; s = e = i; } //情況三,子數組不包含a[i],即b[i]=sum if (bMin < sum) //三種情況相比較,最小值作為更新後的最優解,存在sum { sum = bMin; *start = s; *end = e; } } return sum; }

5、給出10W條人和人之間的朋友關系,求出這些朋友關系中有多少個朋友圈(如A-B、B-C、D-E、E-F,這4對關系中存在兩個朋友圈),并給出算法的時間複雜度。

/朋友圈-并查集 int set[10001]; int find(int x) { int i, j, r; r = x; while (set[r] != r) //尋找此集合的代表 r = set[r]; i = x; while (i != r) //使得r代表的集合中,所有結點直接指向r,即路徑壓縮 { j = set[i]; set[i] = r; i = j; } return r; } void merge(int x, int y) { int t = find(x); int h = find(y); if (t < h) set[h] = t; else set[t] = h; } int friends(int n, int m, int (*r)[2]) //n個人,m對好友關系,存放在二維數組r[m][2]中 { int i, count; for (i = 1; i <= n; i ) set[i] = i; for (i = 0; i < m; i ) merge(r[i][0], r[i][1]); count = 0; for (i = 1; i <= n; i ) { if (set[i] == i) count ; } return count; }

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关職場资讯推荐

热门職場资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved