題目:
假設按照升序排序的數組在預先未知的某個點上進行了旋轉。
( 例如,數組 [0,1,2,4,5,6,7] 可能變爲 [4,5,6,7,0,1,2] )。
搜索一個給定的目標值,如果數組中存在這個目標值,則返回它的索引,否則返回 -1 。
你可以假設數組中不存在重複的元素。
你的算法時間複雜度必須是 O(log n) 級別。
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
-
示例 1:
輸入: nums = [4,5,6,7,0,1,2], target = 0
輸出: 4 -
示例 2:
輸入: nums = [4,5,6,7,0,1,2], target = 3
輸出: -1
分析:
所以挨個查詢, O(N) 時間複雜度肯定是能完成的。 但是題上給出了條件:
其實看到 O(logN)級別 很明顯就是提示你用二分法了
那麼二分法對於這種不是嚴格意義上的遞增遞減數組該怎麼使用呢
我們可以多舉幾個例子來觀察。
* 比如 旋轉後的數組爲 5,6,7,8,1,2,3,4 middle是8 它處於5-8這個遞增序列中,如果此時的target正好 5 < target < 8 那麼,我們就應該在5-8這個子數組中去尋找是否包含這個值,也就是在5-8中繼續使用二分法,即 right = middle - 1。 如果target不在5-8之間,那麼它勢必就在另一頭的遞增序列中,那麼就left = middle + 1;
* 又比如 旋轉後的數組爲 4,5,6,7 1,2,3 middles是7, 它處在4,5,6,7這個遞增序列中。 與上面同理
* 再比如 旋轉後的數組爲 5,6,7,1,2,3,4 middle是1 , 它處在1,2,3,4這個遞增序列中;如果target > nums[middle] && target <= nums[len - 1] 那麼 就應該在 1,2,3,4這個序列中去找,即left = middle + 1; 如果不是這樣的大小關係,那麼就應該 right = middle - 1;
* 所以我們需要判斷 middle落在了旋轉後的哪個遞增序列中。在這個遞增序列中再去使用二分法查找target
代碼
/**
* 二分法
* 不管有序數組如何旋轉,我們總能找到middle 在一個有序子數組中。
* 比如 旋轉後的數組爲 56781234 middle是8 它處於5-8這個遞增序列中
* 又比如 旋轉後的數組爲 4,5,6,7 1,2,3 middles是7, 它處在4,5,6,7這個遞增序列中。
* 所以我們需要判斷 middle落在了旋轉後的哪個遞增序列中。在這個遞增序列中再去使用二分法查找target
* @param nums
* @param target
* @return
*/
public static int searchDemo(int[] nums, int target) {
if (nums.length == 0 || nums == null)
return -1;
int len = nums.length;
int left = 0, right = len - 1, middle;
while (left <= right ){
middle = left - (left - right) / 2;
if(nums[middle] == target)
return middle;
//前半部分有序
if(nums[left] <= nums[middle]){
if(target < nums[middle] && target >= nums[left])
right = middle - 1;
else
left = middle + 1;
}
else {
if(target > nums[middle] && target <= nums[right])
left = middle + 1;
else
right = middle - 1;
}
}
return -1;
}