題目:
假設按照升序排序的數組在預先未知的某個點上進行了旋轉。
( 例如,數組 [0,1,2,4,5,6,7] 可能變為 [4,5,6,7,0,1,2] )。
搜索一個給定的目標值,如果數組中存在這個目標值,則返回它的索引,否則返回 -1 。
你可以假設數組中不存在重復的元素。
你的算法時間復雜度必須是 O(log n) 級別。
示例 1:
輸入: nums = [4,5,6,7,0,1,2], target = 0
輸出: 4
示例 2:
輸入: nums = [4,5,6,7,0,1,2], target = 3
輸出: -1
這道題其實是要我們明確「二分」的本質是什么。
「二分」不是單純指從有序數組中快速找某個數,這只是「二分」的一個應用。
「二分」的本質是兩段性,并非單調性。只要一段滿足某個性質,另外一段不滿足某個性質,就可以用「二分」。
兩段有序值的分布
思路:
二分法:
如上所示我畫了個圖,其實每次我們在判斷中值的時候都會拿到兩個分別是有序的片段,且左端的值是比右端的大的
我們要先根據 nums[mid] 與 nums[l] 的關系判斷 mid 是在左段還是右段,接下來再判斷 target 是在 mid 的左邊還是右邊,從而來調整左右邊界 l 和 r。這樣就做到了我們每次其實都是在一側有序片段上進行比較
class Solution {
public int search(int[] nums, int target) {
int l=0,r=nums.length-1,mid=0;
while (l<=r){
mid=l+(r-l)/2;
if(nums[mid]==target){
return mid;
}
//根據mid和l的關系判斷,mid在左邊還是右邊
//由于左段是恒大于右端的,所以只要mid大于l初,mid必然在左段上
if (nums[mid]>=nums[l]){
//中值大于左側的值,目前mid處于左段,mid左側是升序
//(這里不用寫target<=nums[mid],寫target<nums[mid]就行,因為前面已經比較過,去除這個case了)
if (target>=nums[l]&&target<nums[mid]){
r=mid-1;
}else {
l=mid+1;
}
}else {
//中值小于左邊的值,目前mid處于右端,右側是升序
if (target<=nums[r]&&target>nums[mid]){
l=mid+1;
}else {
r=mid-1;
}
}
}
return mid;
}
}