面試題8 旋轉數組的最小數字
題目描述:把一個數組最開始的若干個元素搬到數組的末尾,我們稱之爲數組的旋轉。輸入一個遞增排序的數組的一個旋轉,輸出旋轉數組的最小元素。例如數組{3,4,5,1,2}爲{1,2,3,4,5}的一個旋轉,該數組的最小值爲 1。
思路
題目本身不難理解,就是一個有序數組的變形,這裏有兩個問題需要考慮:
(1)題目中說的旋轉是一次旋轉還是不限次數?
(2)數組中的數是嚴格遞增還是可以有相同的數出現?
思考
我們先看第一個問題:如果能不限次數的話,那按照題目給的旋轉方式,完全可以將數組旋轉成一個無序數組,那尋找最小值只能是先排序再找最小值了,和題意不符,得出結論:只能旋轉一次;
第二個問題:嚴格遞增是我們想要的,如果是嚴格遞增,那麼二分查找將會非常有用,能有效減小時間複雜度。
考慮元素可以相同,極端情況:有個長度很大的數組,除了第一位是0之外,數組中其餘的數都是1。我們發現,如果對數組進行隨意旋轉操作,那麼0可能在的位置是數組的第2到n位。不能通過判斷大小(因爲只有一個元素不相同)來判斷,那隻能遍歷數組比較大小獲得最小值了。這嚴格來說也不太符合題意。但是在許多其它的答案中都考慮到了這個可能,仁者見仁,那我們也實現它。
代碼
package swordOffer;
/**
* 這是劍指offer的第8題:旋轉數組的最小數字
* 題目描述:把一個數組最開始的若干個元素搬到數組的末尾,我們稱之爲數組的
* 旋轉。輸入一個遞增排序的數組的一個旋轉,輸出旋轉數組的最小元素。例如數
* 組{3,4,5,1,2}爲{1,2,3,4,5}的一個旋轉,該數組的最小值爲 1。
*
* @author Stephen Huge
*
*/
public class Ex08MinAtRotateArr {
public static void main(String[] args) {
Ex08MinAtRotateArr mara = new Ex08MinAtRotateArr();
int[] arr = {2, 3, 4, 5, 1};
// int[] arr = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1};
int sol = mara.MinAtRotateArr(arr);
System.out.println(sol);
}
public int MinAtRotateArr(int[] arr) {
return MinAtRotateArr(arr, 0, arr.length - 1);
}
private int MinAtRotateArr(int[] arr, int left, int right) {
int pivot = (left + right) / 2;
if(arr[left] == arr[right]) {
return iterateGet(arr);
}
if(left == pivot) {
return arr[left + 1];
}
if(arr[left] < arr[pivot]) {
left = pivot;
pivot = (pivot + right) / 2;
}
if(arr[left] > arr[pivot]) {
right = pivot;
pivot = (pivot - left) / 2;
}
return MinAtRotateArr(arr, left, right);
}
// 數組左右數相同時,無法使用二分法判斷,採用遍歷判斷
private int iterateGet(int[] arr) {
int result = arr[0];
for(int i = 1; i < arr.length; i++) {
if(arr[i] < result) {
result = arr[i];
}
}
return result;
}
}
執行結果是:
1