class Solution{
public:
int search(vector<int>& a,int t){//主函式;a旋轉.互異.升序陣列
int l=0,r=(int)a.size()-1;//初始化為整段
while(l<=r){//區間未空持續二分
int m=(l+r)>>1; // 本題無溢位風險
if(a[m]==t) return m;
if(a[l]<=a[m]) (a[l]<=t && t<a[m])? r=m-1: l=m+1;//左半單調有序;若t在[a[l],a[m))收右,否丟到右半
else (a[m]<t && t<=a[r])? l=m+1: r=m-1;//否則右半段有序;若t在(a[m],a[r]]收左,否丟到左半
}
return -1;
}
};
中點二分。
1)步數是對數級。
2)判斷哪側有序,目標若在有序側就收縮到那側。
3)每輪區間嚴格變小,必收斂,不卡。
左半有序情況
陣列:[4,5,6,7,0,1,2],l=0,r=6 ⇒ m=(0+6)/2=3,a[m]=7
a[l]=4 ≤ a[m]=7,左半 [4,5,6,7] 有序。
t=5:落在 [a[l],a[m))=[4,7) ⇒ r=m−1=2(收右界)。
右邊界改成 m-1,丟掉「中點含右邊」那一半,只在左半段找。
例:l=0,r=6,m=3 → 設 r=m-1=2,區間變成 [0..2]。
t=0:不在該區間 ⇒ l=m+1=4(丟到右半段)。
1)「不在該區間」指:左半有序區間的值域是 [a[l], a[m])=[4,7)。因為 0 不落在 [4,7) 裡,所以判定「不在該區間」。
2)因此丟掉左半,把左邊界設為中點右一格:l=m+1=3+1=4。新搜尋區間變成索引 [4..6],數值是 [0,1,2]。
右半有序情況
同陣列,取 l=3,r=6 ⇒ 子陣列 [7,0,1,2],m=(3+6)/2=4,a[m]=0
因 a[l]=7 > a[m]=0,故右半 [0,1,2] 有序。
t=2:落在 (a[m],a[r]]=(0,2] ⇒ l=m+1=5(收左界,保留右半)。
t=7:不在該區間 ⇒ r=m−1=3(收右界,轉向左半)。