演算法--旋轉陣列二分查詢
旋轉陣列 將一個有序陣列前一部分移到後端 例如 12345---34512
1.求旋轉陣列的最小值
陣列基本有序可以考慮二分查詢來解決,考慮旋轉陣列的特點前半部分遞增後半部分遞減,使用兩個指標,第一個index1指向遞增部分,第二個index2指向遞減部分,不斷逼近,當兩者距離之差index2-index1等於1,可以得到最小值為第二個指標index2位置的數值。
求出中點值 mid
四種情況,
1.index2-index1==1 此時最小值即為arr[index2].
2.mid在前半部分 3,4,5,6,7,8,9,0,1,2 判斷特徵為 arr[mid]>arr[index1] && arr[mid]>arr[index2],此時最小值肯定在mid右邊 即index1=mid;
3.mid在後半部分 7,8,9,0,1,2,3,4,5,6 判斷特徵為 arr[mid]<arr[index1] && arr[mid]<arr[index2]此時最小值在mid左邊 index2=mid;
4.如果arr[index1]==arr[mid]==arr[index2] 此時無法判斷最小值在mid兩邊位置,只能遍歷查詢最小值。
public static int minNum(int[] arr){ int index1 = 0; int index2 = arr.length-1; int min = arr[index2]; while(index1 < index2){ System.out.println(index1 + " " + index2); if(index2 - index1==1){ min = arr[index2]; break; } int mid = (index1 + index2) >> 1; if(arr[mid]>arr[index1] && arr[mid]>arr[index2]) index1 = mid; else if(arr[mid]<arr[index1] && arr[mid]<arr[index2]) index2 = mid; else{ for(int i=index1; i<index2; i++){ if(arr[i]<min) min = arr[i]; } } } return min; }
2.旋轉陣列查詢某一個數字
陣列基本有序,考慮二分查詢 lo hi mid指標
1.如果arr[mid]==num 直接返回mid
2. mid值在前半部分 如 3,4,5,6,7,8,9,0,1,2 判斷特徵: arr[mid]>arr[lo] && arr[mid]>arr[hi]
比較arr[mid]與num關係:
在mid左邊 arr[lo]<=num<arr[mid](注意等號取值,否則端點處值查詢不到) mid左邊此時完全有序,可以利用二分查詢
在mid右邊 mid右邊陣列為先增後減,即為一個旋轉陣列的查詢的遞迴問題
3. mid值在後半部分 如7,8,9,0,1,2,3,4,5,6 判斷特徵 arr[mid]<arr[lo] && arr[mid]<arr[hi]
比較arr[mid]與num關係:
在mid右邊 arr[mid]<num<=arr[hi ]mid右邊陣列為完全有序,二分查詢
在mid左邊 mid左邊陣列也是一個旋轉陣列 原來問題的遞迴問題
public static int findNum(int[] arr, int num, int lo, int hi){
int mid = (lo + hi) >> 1;
if(arr[mid]==num)
return mid;
else if(arr[mid]>arr[lo] && arr[mid]>arr[hi]){
// arr[lo]<=num num<=arr[hi] 取值等號為了處理邊界情況,確定目標值所在範圍然後執行二分查詢
if(arr[lo]<=num && num<arr[mid])
return binaryFind(arr, num, lo, mid);
else
return findNum(arr, num, mid, hi);
}else{
if(arr[mid]<num && num<=arr[hi])
return binaryFind(arr, num, mid, hi);
else
return findNum(arr, num, lo, mid);
}
}
public static int binaryFind(int[] arr, int num, int lo, int hi){
while(lo<=hi){
int mid = (lo+hi)>>1;
if(arr[mid]==num)
return mid;
else if(arr[mid]<num)
lo = mid + 1;
else
hi = mid - 1;
}
return -1;
}
對於旋轉陣列基本有序,查詢時可以考慮二分查詢。由於陣列特點是先增後減,前半部分與後半部分長度未定,因此首先需要判斷mid中點值的位置,在前半部分還是後半部分,根據中點值可以將原陣列劃分為 一個旋轉陣列以及一個完全有序的數字,因此可以遞迴來解決問題。