描述:把一個數組最開始的若幹個元素搬到數組的末尾,我們稱之為數組的旋轉。輸入一個遞增排序的數組的一個旋轉,輸出旋轉數組的最小元素,排序的旋轉數組定義如下:
如:{1,2,3,4,5}的一個旋轉數組為{3,4,5,1,2} 該數組的最小值為1
複制
初看題目我們最直覺的解法并不難,周遊數組用倆個"指針"一前以後,目前面"指針"指向的元素比後面的"指針"指向的數組元素小時,這時我們就找到旋轉數組中的最小元素,我們不難寫出如下代碼:
public static int findMin(int[] arr) {
// 如果數組是隻有一個元素 則不是旋轉數組同時也防止下邊的i+1越界
if(arr == null || arr.length <= 1){
return -1;
}
for (int i =0 ; i < arr.length -1; i++) {
if (arr[i] > arr[i + 1]) {
return arr[i + 1];
}
}
return -1;
}
複制
但是上面這種方法當數組的元素特别多時,效率是比較低的,不足以拿到offer,現在考慮用二分法對上面算法進行改良:
定義一個數組最左邊的"指針"left和一個數組最右邊的"指針"right,每次求倆個指針的中間值記為middle,如果left所對應的值要比middle小,那麼說明數組還在遞增中,最小值會在middle和right之間,這時候我們讓left等于middle,繼續用同樣的方式縮小範圍,如果middle要比right小,那麼說明最小值在left和middle之間,讓right等于middle,用同樣的方式繼續求下去,就能求到最小值啦。
public static int findMin(int []arr) {
int left = 0;
int right = arr.length;
while(left < right) {
int middle = (left + right) / 2;
if (arr[left] < arr[middle]) {
left = middle;
// 如果遇到相同的元素 我們就隻能用周遊了
} else if(arr[left] == arr[middle]){
for(int i = left; i <= middle; i++) {
if(arr[i] < arr[middle]) {
return arr[i];
}
}
return arr[left];
} else{
right = middle;
}
if (right - left == 1) {
if(arr[right] > arr[left])
return arr[left];
else
return arr[right];
}
}
return arr[left];
}
複制
當left對應的元素與right對應的元素相等時,這是特殊情況,這裡選擇周遊去找最小值。