筆者由於在找工作,所以近期最主要的任務就是準備面試,不打無準備之仗。只有你準備充分了,那麼你想要的機會纔有機會入你懷中。
筆者會將準備面試的學習過程記錄下來,方便自己覆盤的同時也希望能給一道找工作的小夥伴們一些幫助。筆者準備的內容大綱如下
下面是本篇博客的正菜部分:
一、找出數組中重複的數字
在一個長度爲n的數組裏的所有數字都在0~n-1的範圍內。找出數組中任意一個重複的數字。
注意:如果題目改成找出數組中重複的數字的話,就需要和面試官溝通,我是找出所有重複的數字還是只需要找出一個就好了。
排序法
先把原數組進行一次排序,再對排序好的數組從頭到尾進行遍歷,很容易找到重複的數字,排序長度爲n的數組需要O(nlogn)的時間。
哈希表法
可以藉助哈希表解決該問題,從頭到尾掃描該數組,判斷該掃描到的數是否存在於該哈希表中,如果不存在則放於該哈希表中,如果存在則爲重複元素。這個算法的時間複雜度是O(n),但卻是以大小爲O(n)的空間複雜度爲代價。
交換法
如果沒有重複元素的話,那麼重排該數組後,數字i會出現在下標i的位置。如果有重複元素的話,下標i的位置可能不止一個數字,也可能沒有數字。
從頭到尾掃描數組,掃描到下標爲i的數字(用m表示)看是否等於i,如果是則接着掃描下一個數字,如果不是,再拿它和下標爲m的那個數字比較,如果相等,則找到一個重複數字,如果不相等,就和它交換。重複這樣的操作,直到找到重複的數字。
代碼實例:
如果不存在重複元素的話,返回-1(具體返回的值可以和面試官溝通)
public int getDuplicateNumber(int[] numbers){
int len = numbers.length;
if(numbers == null || len <= 0) return -1;
for(int i=0;i<len;i++){
if(numbers[i] < 0 || numbers[i] > len-1)
return -1;
}
for(int i=0;i<len;i++){
while(numbers[i] != i){
if(numbers[i] == numbers[numbers[i]]){
return numbers[i]; //找到重複元素
}
else {
//交換numbers[i]和numbers[numbers[i]]的值
int temp = numbers[i];
numbers[i] = numbers[temp];
numbers[temp] = temp;
}
}
}
return -1;
}
二、不能修改數組找出重複的數字
在一個長度爲n+1的數組裏的所有數字都在1~n的範圍內。找出數組中任意一個重複的數字。不能改變原數組並且不可藉助大小超過O(n)的輔助空間。
二分法
因爲長度是n+1,所以該數組至少有一個重複的數字。可以根據長度進行一半一半的分割。比如長度爲8的數組,把它分兩半:1-4,5-7。先在數組中找在1-4範圍內的數的個數,如果超過4個說明重複的數字在1-4中。這樣就縮小了範圍,之後繼續二分,在數組中分別找1-2,3-4這兩組數字的個數,直到找到一個重複的數字。
public int getDuplicateNumber2(int[] numbers){
int len = numbers.length;
if(numbers == null || len <= 0) return -1;
int start = 1;
int end = len-1;
while(end >= start){
int middle = ((end - start) >> 1)+start;
int count = countRange(numbers,len,start,middle);
if(end == start){
if(count > 1) return start; //找到重複元素
else break;
}
if(count >(middle-start+1))
end = middle;
else
start = middle+1;
}
return -1;
}
private int countRange(int[] numbers, int len, int start, int end) {
if(numbers == null)
return 0;
int count = 0;
for(int i=0;i<len;i++){
if(numbers[i]>=start && numbers[i]<=end)
++count;
}
return count;
}
參考:劍指offer P39
面試系列的文章都放於 面試妥妥的 建議小夥伴們關注該專題