一、概述
這題目出的有點模糊,“rotated at some pivot”,你這個some,到底是一個轉折點還是好幾個啊,查了一下pivot,可數名詞,單數,所以應該是一個。不然想一下極端情況,對於1234,調轉二次變成2143,那這個有序性就被完全破壞掉了,這個條件就沒卵子用。這樣不行。所以只調轉一次。
接下來看時間要求,logn,穩了,用二分肯定沒錯。
二、分析
傳統的二分法是應用於有序數組的,中間的和target比,target大於mid就找後面,target小於mid就找前面。爲什麼這麼自信?因爲target大於mid就表明target大於左邊最大值;同理小於。
現在問題來了,這個數組不是完全有序的,而是分段有序。那麼如果我們分成[left,mid]和[mid,right]兩個區間,就一定有一個區間完全有序,而另外一個部分有序。因爲轉折點只有一個,所以轉折點所在的區間部分有序,轉折點不在的區間完全有序。
對於完全有序的區間,可以判斷target在不在該區間內,即用target與該區間的左右端點比較,小於左端點或大於右端點說明不在,否則就在。這樣就可以確定target在左區間還是右區間了。
如何判斷轉折點在哪個區間呢?我們來看以下幾個例子:
12345678,轉折點位於8(從0開始,第8個,即不存在),left=1,mid=4,right=8;
23456781,轉折點位於7,left=2,mid=5,right=1;
34567812,轉折點位於6,left=3,mid=6,right=2;
45678123,轉折點位於5,left=4,mid=7,right=3;
56781234,轉折點位於4,left=5,mid=8,right=4;
67812345,轉折點位於3,left=6,mid=1,right=5;
78123456,轉折點位於2,left=7,mid=2,right=6;
81234567,轉折點位於1,left=8,mid=3,right=7;
可以看出一個規律:轉折點位於的區間,該區間的左端點值大於右端點。因此可以用這個來判斷。
代碼如下:
class Solution {
public:
int search(vector<int>& nums, int target) {
int len=nums.size();
if(len==0)
return -1;
if(len==1)
if(nums[0]!=target)
return -1;
else
return 0;
int left=0,right=len-1;
int mid=(left+right)/2;
while(left!=right)
{
if(nums[mid]==target)
return mid;
if(nums[left]>nums[mid])//右側正常
{
if(nums[mid]>target||nums[right]<target)
{
right=mid-1;
}
else
{
left=mid+1;
}
}
else//左側正常
{
if(nums[left]>target||nums[mid]<target)
{
left=mid+1;
}
else
{
right=mid-1;
}
}
mid=(left+right)/2;
}
if(nums[left]==target)
return left;
else
return -1;
}
};
三、總結
稍微有點彎彎繞,知道用二分法就很簡單了。