1. 程式人生 > >演算法--旋轉陣列二分查詢

演算法--旋轉陣列二分查詢

旋轉陣列   將一個有序陣列前一部分移到後端 例如  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中點值的位置,在前半部分還是後半部分,根據中點值可以將原陣列劃分為  一個旋轉陣列以及一個完全有序的數字,因此可以遞迴來解決問題。