假設按照升序排序的數組在預先未知的某個點上進行了旋轉。( 例如,數組 [0,1,2,4,5,6,7] 可能變爲 [4,5,6,7,0,1,2] )。
搜索一個給定的目標值,如果數組中存在這個目標值,則返回它的索引,否則返回 -1 。
你可以假設數組中不存在重複的元素。你的算法時間複雜度必須是 O(log n) 級別。
可以用二分法查找,但是邊界處理需要多一些判斷。假設數組爲nums,元素中最小值索引爲k(即下面圖中0的位置),則根據k所在的位置,可以分爲三種情況:第一種就是k即是在數組的開始位置,這種情況下直接用正常的二分法即可,判斷數組中間值nums[m]與target選擇左邊繼續二分還是右邊繼續二分;第二種如圖1所示,此時k在m和e之間,即起始點(最小值)在右半部分的情況,這個時候左半邊一定是有序即nums[s]<=nums[m],則我們只需要判斷target是否在nums[s]和nums[m]之間即可知道target是屬於左半邊還是右半邊,然後再對左半邊或右半邊進行同樣操作即可;第三種如圖2所示,此時k在s和m之間,即起始點在左半邊的情況,這個時候右半邊一定是有序即nums[m]<=nums[e],則我們可以判斷target是否在nums[m]和nums[e]之間即可知道target是屬於左半邊還是右半邊了,剩下的操作和第二種情況差不多。
實際上我們是不知道也不需要知道k的位置的,k位置的假設只是讓我們更容易的分清三種情況。
實現代碼如下:
class Solution {
public:
int search(vector<int>& nums, int target) {
int s = 0, m = 0, e = nums.size() - 1;
while (s <= e) {
m = s + (e - s) / 2;
if (nums[m] == target) {
return m;
}
if (nums[s] > nums[m]) {
// 起始點在中分點左邊
if (nums[m] < target && nums[e] >= target) {
s = m + 1;
}
else {
e = m - 1;
}
}
else if (nums[m] > nums[e]) {
// 起始點在中分點右邊
if (nums[m] > target && nums[s] <= target) {
e = m - 1;
}
else {
s = m + 1;
}
}
else {
// 當前分段沒有起始點,或起始點就在s位置
if (nums[m] < target) {
s = m + 1;
}
else {
e = m - 1;
}
}
}
return -1;
}
};