最近在微博上看到一道有趣的GOOGLE面試題,見下圖:java
文字版:面試
一個大小爲n的數組,裏面的數都屬於範圍[0, n-1],有不肯定的重複元素,找到至少一個重複元素,要求O(1)空間和O(n)時間。算法
這個題目要求用O(n)的時間複雜度,這意味着只能遍歷數組一次。同時還要尋找重複元素,很容易想到創建哈希表來完成,遍歷數組時將每一個元素映射到哈希表中,若是哈希表中已經存在這個元素則說明這就是個重複元素。所以直接使用C++ STL中的hash_set(參見《STL系列之六 set與hash_set》)能夠方便的在O(n)時間內完成對重複元素的查找。windows
可是題目卻在空間複雜度上有限制——要求爲O(1)的空間。所以採用哈希表這種解法確定在空間複雜度上是不符合要求的。但能夠沿着哈希法的思路繼續思考,題目中數組中因此數字都在範圍[0, n-1],所以哈希表的大小爲n便可。所以咱們實際要作的就是對n個範圍爲0到n-1的數進行哈希,而哈希表的大小恰好爲n。對排序算法比較熟悉的同窗不難發現這與一種經典的排序算法——基數排序很是相似。而基數排序的時間空間複雜度恰好符合題目要求!所以嘗試使用基數排序來解這道面試題。數組
下面以2,4,1,5,7,6,1,9,0,2這十個數爲例,展現下如何用基數排序來查找重複元素。spa
下標.net |
0code |
1blog |
2排序 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
數據 |
2 |
4 |
1 |
5 |
7 |
6 |
1 |
9 |
0 |
2 |
(1)因爲第0個元素a[0] 等於2不爲0,故交換a[0]與a[a[0]]即交換a[0]與a[2]得:
下標 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
數據 |
1 |
4 |
2 |
5 |
7 |
6 |
1 |
9 |
0 |
2 |
(2)因爲第0個元素a[0] 等於1不爲0,故交換a[0]與a[a[0]]即交換a[0]與a[1]得:
下標 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
數據 |
4 |
1 |
2 |
5 |
7 |
6 |
1 |
9 |
0 |
2 |
(3)因爲第0個元素a[0] 等於4不爲0,故交換a[0]與a[a[0]]即交換a[0]與a[4]得:
下標 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
數據 |
7 |
1 |
2 |
5 |
4 |
6 |
1 |
9 |
0 |
2 |
(4)因爲第0個元素a[0] 等於7不爲0,故交換a[0]與a[a[0]]即交換a[0]與a[7]得:
下標 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
數據 |
9 |
1 |
2 |
5 |
4 |
6 |
1 |
7 |
0 |
2 |
(5)因爲第0個元素a[0] 等於9不爲0,故交換a[0]與a[a[0]]即交換a[0]與a[9]得:
下標 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
數據 |
2 |
1 |
2 |
5 |
4 |
6 |
1 |
7 |
0 |
9 |
(6)因爲第0個元素a[0] 等於2不爲0,故交換a[0]與a[a[0]]即交換a[0]與a[2],但a[2]也爲2與a[0]相等,所以咱們就找到了一個重複的元素——2。
下標 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
數據 |
2 |
1 |
2 |
5 |
4 |
6 |
1 |
7 |
0 |
9 |
package sample; /** * 一個大小爲n的數組,裏面的數都屬於範圍[0, n-1],有不肯定的重複元素, * 找到至少一個重複元素,要求O(1)空間和O(n)時間。 * @author markGao * */ public class GoogleInterview { static int NO_REPEAT_FLAG = -1; // 相似於基數排序,找出數組中第一個重複元素。 static int RadixSort(int a[], int n) { int i; for (i = 0; i < n; i++) { while (i != a[i]) { if (a[i] == a[a[i]]) return a[i]; int temp; temp = a[a[i]]; a[a[i]] = a[i]; a[i] = temp; } } return NO_REPEAT_FLAG; } static void PrintfArray(int a[], int n) { for (int i = 0; i < n; i++) System.out.printf("%d ", a[i]); System.out.print('\n'); } public static void main(String[] args) { System.out.printf(" 白話經典算法系列之十 一道有趣的GOOGLE面試題 \n"); int MAXN = 10; int a[] = { 2, 4, 1, 5, 7, 6, 1, 9, 0, 2 }; // int a[MAXN] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; System.out.printf("數組爲: \n"); PrintfArray(a, MAXN); int nRepeatNumber = RadixSort(a, MAXN); if (nRepeatNumber != NO_REPEAT_FLAG) System.out.printf("該數組有重複元素,此元素爲%d\n", nRepeatNumber); else System.out.printf("該數組沒有重複元素\n"); } }