1. 程式人生 > >旋轉陣列的最小數字(Java)

旋轉陣列的最小數字(Java)

題目:

把一個數組最開始的若干個元素搬到陣列的末尾,我們稱之為陣列的旋轉。輸入一個遞增排序的陣列的一個旋轉,輸出旋轉陣列的最小元素。例如陣列{3, 4, 5, 1, 2}為{1, 2, 3, 4, 5}的一個旋轉,該陣列的最小值為1。

第一思路:

剛拿到這道題我相信大多數人和我一樣想到了時間複雜度為O(n)的查詢演算法,即遍歷一遍陣列找到自己滿足題意的最小值元素。可以如果這樣做,就違背了題意旋轉陣列,即沒有利用旋轉陣列中的兩部分有序原則。故需再思考。

最優思路:

(1)旋轉陣列實際上可以劃分為兩個排序的子陣列,而且前面的子陣列元素都大於或者等於後面的子陣列的元素;(2)最小的元素剛好是這兩個字陣列的分界線;因為在排序的陣列中我們可以用二分查詢法實現O(logn)的查詢。故旋轉陣列找最小元素值也可以採取二分查詢的思路。

首先我們定義兩個指標p1指向陣列的第一個元素和p2指向陣列的最後一個元素,接著我們找到中間的元素。如果該元素位於前面遞增陣列中,它應該大於或者等於第一個指標指向的元素,我們將p1指向中間元素;如果中間元素位於後面的遞增陣列中,那麼它應該小於或者等於第二個指標指向的元素,我們把p2指向中間元素。不管移動p1還是p2,查詢的範圍都會縮小為原來一半,接下來利用更新後的兩個指標重複上面的查詢。按照上面的思路,p1始終在前面遞增陣列,p2始終在後面遞增陣列,最終p1會指向前面子陣列的最後一個元素,第二個指標會指向後面子陣列的第一個元素,即最小元素,結束迴圈。

有一特例是p1、p2和中間值都相等,這時候就老老實實迴圈遍歷一次陣列,找到最小值。

程式碼:

public class Main {

	//一般情況時的查詢演算法
	public int Min(int arrays[]){
		if(arrays == null){
			try {
				throw new Exception("Invalid parameters");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		int index1 = 0;
		int index2 = arrays.length - 1;
		int indexMid = index1;
		while(arrays[index1] > arrays[index2]){
			if(index2 - index1 == 1){ //如果差值為1,則index2下標的數一定是最小數
				indexMid = index2;
				break;
			}
			indexMid = ( index1 + index2 ) / 2; //取中間值
			if(arrays[index1] == arrays[index2] && arrays[indexMid] == arrays[index1]){ //特例
				return MinInOrder(arrays);
			}
			if(arrays[indexMid] >= arrays[index1]){ //如果中間值大於index1對應的值,則修改index1的值為中間值
				index1 = indexMid;
			}else if(arrays[indexMid] <= arrays[index2]){ //否則修改index2的值為中間值
				index2 = indexMid;
			}
		}
		return arrays[indexMid]; //indexMid對應的一定是最小值
	}
	//特例時的查詢演算法
	private int MinInOrder(int[] arrays) {
		int result = arrays[0];
		for (int i = 0; i < arrays.length; i++) {
			if(result > arrays[i]){
				result = arrays[i];
			}
		}
		return result;
	}
	//測試
	public static void main(String[] args) {
		int num1[] = {4, 5, 6, 7, 1, 2, 3};
		int num2[] = {1, 0, 1, 1, 1};
		int num3[] = {1, 1, 1, 0, 1};
		Main m1 = new Main();
		System.out.println(m1.Min(num3));
		System.out.println(m1.Min(num2));
		System.out.println(m1.Min(num1));
	}
}

小結:

這道題是二分查詢的變形,考查二分查詢。以及接收新事物的理解能力與轉化能力。