劍指offer_11_旋轉數組中的最小數字

  • 2019 年 10 月 6 日
  • 筆記

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

初看題目我們最直觀的解法並不難,遍曆數組用倆個"指針"一前以後,當前面"指針"指向的元素比後面的"指針"指向的數組元素小時,這時我們就找到旋轉數組中的最小元素,我們不難寫出如下程式碼:

public static int findMin(int[] arr) {      // 如果數組是只有一個元素 則不是旋轉數組同時也防止下邊的i+1越界      if(arr == null || arr.length <= 1){          return -1;      }        for (int i =0 ; i < arr.length -1; i++) {          if (arr[i] > arr[i + 1]) {              return arr[i + 1];          }      }      return -1;  }

但是上面這種方法當數組的元素特別多時,效率是比較低的,不足以拿到offer,現在考慮用二分法對上面演算法進行改良:

定義一個數組最左邊的"指針"left和一個數組最右邊的"指針"right,每次求倆個指針的中間值記為middle,如果left所對應的值要比middle小,那麼說明數組還在遞增中,最小值會在middle和right之間,這時候我們讓left等於middle,繼續用同樣的方式縮小範圍,如果middle要比right小,那麼說明最小值在left和middle之間,讓right等於middle,用同樣的方式繼續求下去,就能求到最小值啦。

public static int findMin(int []arr) {      int left = 0;      int right = arr.length;      while(left < right) {          int middle = (left + right) / 2;          if (arr[left] < arr[middle]) {              left = middle;          // 如果遇到相同的元素 我們就只能用遍歷了          } else if(arr[left] == arr[middle]){              for(int i = left; i <= middle; i++) {                  if(arr[i] < arr[middle]) {                      return arr[i];                  }              }              return arr[left];          } else{              right = middle;          }          if (right - left == 1) {              if(arr[right] > arr[left])                  return arr[left];              else                  return arr[right];          }      }      return  arr[left];  }

當left對應的元素與right對應的元素相等時,這是特殊情況,這裡選擇遍歷去找最小值。