把一個數組最開始的若干個元素搬到數組的末尾,咱們稱之爲數組的旋轉。 輸入一個非遞減排序的數組的一個旋轉,輸出旋轉數組的最小元素。 例如數組{3,4,5,1,2}爲{1,2,3,4,5}的一個旋轉,該數組的最小值爲1。 NOTE:給出的全部元素都大於0,若數組大小爲0,請返回0.算法
發現用二分法解決這個問題很好,{3,4,5,1,2}能夠分紅兩個排好序的子數組{3,4,5}{1,2},而左邊的每一個數必定大於右邊的每一個數,因此能夠聲明兩個索引left=0,right=length-1,mid=left(爲啥這麼設置初始值請看代碼註釋).
開始循環,循環條件爲list[left] >= list[right]。咱們要作的事情就是讓left一直處於第一個數組裏且不斷接近第一個數組尾,讓right一直處於數組二且不斷接近數組二的頭。讓mid等於(left+right)/2,當mid大於left時,說明此時mid還在第一個數組裏,這時就讓left=mid;繼續循環mid再等於(left+right)/2,假設此時mid小於left了,那麼它必定處於第二個數組裏了,並且它也小於right(由於right時第二個數組當前最大的).當left+1==right的時候就能夠跳出循環了,由於此時right就是咱們要找的元素。數組
public class Jianzhi{ public static void main (String[] args){ int[] num = {3,4,5,1,2}; int m = find(num ) ; System.out.println(m); } public static int find(int[] list) { if(list == null){ //數組爲null時 return -1 ; } if(list.length == 0 ){ //數組長度爲0則返回0 return 0 ; } int left = 0 ; int right = list.length - 1 ; int mid = left ; //注意:這一步讓mid等於left是有用意的,若是list是排好序的, //那麼直接返回list[mid] while(list[left] >= list[right]){ if(left + 1 == right){ return right ; } mid = (left + right) / 2 ; if(list[mid] == list[left] && list[mid] == list[right]){ return minInOrder(list,left,right); } if(list[mid] >= list[left]){ left = mid ; } if(list[mid] <= list[right] ){ right = mid ; } } return list[mid] ; } public static int minInOrder(int[] list , int left , int right ){ int result = list[left] ; for(int i = left+1 ; i < right ; i++){ if(result > list[i] ){ result = list[i] ; } } return result ; } }
可能你們比較疑惑爲何有如下這句:spa
if(list[mid] == list[left] && list[mid] == list[right]){ return minInOrder(list,left,right); }
考慮下面這種狀況code
此時 第一個和第二個索引以及mid索引指向的指都是1,三個數字相同。但咱們不能區分出最小的數字在mid的左邊仍是右邊,就無法進行判斷了。此時,就不得不採用順序查找方法:排序
public static int minInOrder(int[] list , int left , int right ){ int result = list[left] ; for(int i = left+1 ; i < right ; i++){ if(result > list[i] ){ result = list[i] ; } } return result ; }
整個算法最重要的仍是讓left和right都往兩個數組的公共邊界靠攏。索引
完畢。圖片