小米筆試題(查找旋轉數組中的元素)

今天參加小米現場筆試,遇到一個關於查找旋轉數組中的元素算法問題,在這裏記錄一下。題目大致如下:給定一個有序數組,如{1,2,3,4,5,6,7,8,9},我們將對這個數組進行選擇,未知從什麼位置旋轉。下面給出一個可能的旋轉結果。如{4,5,6,7,8,9,1,2,3},我們可以理解爲它從元素4位置開始旋轉。之後給定一個指定的數字n,讓我們從{4,5,6,7,8,9,1,2,3}這個數組中找出它的位置,要求時間複雜度儘可能的低。

拿到這個題目,我們很容易的想到,可以直接遍歷一次數組,在時間複雜度爲O(n)的情況下可以找到這個元素。但是我們並沒有利用到這個數組是有序的前提條件。事實上,如果我們仔細觀察的話,可以發現這個數組集合其實可以理解爲是2個非遞減的有序集合。{4,5,6,7,8,9,1,2,3}這個集合可以劃分爲{4,5,6,7,8,9}和{1,2,3}。如果我們可以找到這個拐點,那麼我們也可以很輕鬆的在O(lgn)的時間複雜度下,利用二分查找找出該元素。那麼我們如何找出這個拐點呢,其實在O(lgn)的時間複雜度下可以找到。

在這裏我們不妨在觀察一下這個數組的特性。當我們選取一個拐點,將這個數組進行選擇的時候,我們可以發現,從數組的中間元素開始,可以將這個數組劃分爲兩個子數組。並且必然有一邊的數組是有序的集合。{4,5,6,7,8,9,1,2,3},該例中,middle元素爲8,我們發現了他的左邊元素爲{4,5,6,7}是一個有序的集合。如果我們要查找的元素恰好在這個有序的數組內,那麼只需要利用二分查找,便可以很快地找出這個元素。當然,我們需要一個條件來判斷該元素是否在這個集合中。例:我們現在要查找的數爲n if(n<array[middle]&&n>array[low]) 如果我們當前查找的數,小於middle元素,並且大於左邊最小的元素。其實就可以理解爲左邊的數組是有序的了。我們就可以在左邊集合中進行查找;反之,我們需要在右側數組中查找該元素。

下面貼上代碼

public static int search(int n,int[] array){
		int low = 0;		
		int high = array.length-1;
		while(low<=high){
			int middle = (low+high)/2;
			if(array[middle]==n) return middle;
			if(array[middle]>array[low]){  //left is order
				if(n<=array[middle]&&n>=array[low]){
					high = middle-1;
				}else {
					low = middle+1;
				}
			}else {			
				if(n>=array[middle]&&n<=array[high]){
					low = middle+1;
				}else {
					high = middle-1;
				}
			}
		}
		return -1;	
	} 



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章