1.旋轉數組中的最小數字:(3,4,5,1,2 為 1,2,3,4,5 的一個旋轉)
正如上圖所示:我們計算中間的位置 middle 如果說 arr[middle] >= arr[start] 說明 middle 落在了前面的遞增區間上,middle = start 縮小查找范圍.
同理,如果arr[middle] <= arr[end] 則將 end = middle
這里呢有一個問題:
int MinInorder(int* arr, int start, int end) { int result = arr[start]; bool check = false; while (start <= end) { ++start; if (arr[start] < result) return arr[start]; } return result; } int Min(int* arr, int lenth) { if (arr == NULL || lenth <= 0) { cout << "Error:Invalid Parameters" << endl; return 0; } int start = 0, middle, end = lenth - 1; while (start < end) { middle = (end - start) / 2 + start; if (end - start == 1) return arr[end]; if (arr[middle] == arr[start] && arr[middle] == arr[end]) return MinInorder(arr + start, start, end); if (arr[middle] >= arr[start]) //非特例情況下 start = middle; else end = middle; } }
2.旋轉數組中查找某一個數:(7,8,9,1,2,3,4,5,6 中找 1 返回 3)
int Inorder(int* arr, int left, int right,int key) { for (int i = left; i <= right; ++i) { if (arr[i] == key) return i; } return -1; } int BinarySearch(int* arr, int left, int right, int key) { if (left <= right) { int middle = (right - left) / 2 + left; if (arr[middle] > key) { right = middle - 1; return BinarySearch(arr, left, right, key); } else if (arr[middle] < key) { left = middle + 1; return BinarySearch(arr, left, right, key); } else return middle; } return -1; } int RotateArray(int* arr, int _left,int _right, int key) { int left = _left, right = _right, middle = (_left + _right) / 2 + left; if (arr[left] == arr[middle] && arr[middle] == arr[right]) //如果 arr[left] == arr[middle] && arr[right] == arr[middle] 此時不能確定左是單增還是右是單增 { Inorder(arr, left, right, key); } else if (arr[left] <= arr[middle]) //前半部分為單增區間 { if (key >= arr[left] && key <= arr[middle]) //如果key落在了前半部分則使用折半查找法 { return BinarySearch(arr, left, middle, key); } else { return RotateArray(arr, middle + 1, right, key); } } else //后半部分為單增區間 { if (key > arr[middle] && key <= arr[right]) { return BinarySearch(arr, middle+1, right, key); } else { return RotateArray(arr, left, middle, key); } } }
3.找出一個排序數組中的 K 出現的次數
解決思路:假設我們是統計數字k在排序數組中出現的次數,只要找出排序數組中第一個k與最后一個k的下標,就能夠計算出k的出現次數。
尋找第一個k時,利用二分查找的思想,我們總是拿k與數組的中間元素進行比較。如果中間元素比k大,那么第一個k只有可能出現在數組的前半段;如果中間元素等於k,我們就需要判斷k是否是前半段的第一個k,如果k前面的元素不等於k,那么說明這是第一個k;如果k前面的元素依舊是k,那么說明第一個k在數組的前半段中,我們要繼續遞歸查找。 同樣的思路,我們在數組中尋找最后一個k,如果中間元素比K大,那么k只能出現在數組的后半段;如果中間元素比K小,那么K只能出現在數組的前半段。如果中間元素等於k,而k后面的元素等於k,那么最后一個k只能在后半段出現;否則k為數組中最后的一個k。
/*排序數組中的K出現的次數*/ int GetFirstK(int* arr, size_t size, int value) { assert(arr); int start = 0,middle, end = size - 1; while (start <= end) { middle = (end - start) / 2 + start; if (arr[middle]>value) end = middle - 1; else if (arr[middle] < value) start = middle + 1; else { if (middle - 1 >= 0 && arr[middle - 1] == value) end = middle - 1; else return middle; } } return -1; }
int GetLastK(int* arr, size_t size, int value) { assert(arr); int start = 0, middle, end = size - 1; while (start <= end) { middle = (end - start) / 2 + start; if (arr[middle]>value) end = middle - 1; else if (arr[middle] < value) start = middle + 1; else { if (middle + 1 < size && arr[middle + 1] == value) start = middle + 1; else return middle; } } return -1; }
int GetNumberOfK(int* arr, int size, int value) { if (arr == NULL || size <= 0) return -1; int First = GetFirstK(arr, size, value); int Last = GetLastK(arr, size, value); if (First >= 0) // 說明value一定存在 return (Last - First + 1); }