二分是一個經常使用的小技巧,能夠將本來O(n)的複雜度降爲O(log n)。可是二分也有侷限性,只能在一個單調有序的集合中使用,因此,對於一道題目,咱們要先判斷它是否具備可二分性,而後再進行二分。數組
1.二分查找函數
思路:spa
在一個不嚴格單調的有序集合中,咱們若是要查找一個元素的位置,能夠用l來存儲下界,用r來存儲上界,而後將整個集合分紅兩半,經過對集合中間元素與目標元素的比較,來判斷目標元素是在集合中的左半部分仍是右半部分(若是中間元素與目標元素相同,則退出函數,返回中間元素的位置),隨後更新上界和下界。不斷進行這樣的操做,直至l>r爲止。.net
代碼:code
1 //這裏以在一個不嚴格單調遞增數組中查找元素爲例 2 int find(int l,int r,int v)//l存儲上界,r存儲下界,v即爲目標元素 3 { 4 if(l>r) return -1;//若是找不到就返回-1 5 int mid=(l+r)>>1;//mid即爲中間元素的位置,這裏用位運算提升效率,至關於"int mid=(l+r)/2;"(位運算請見https://blog.csdn.net/chenxiaoran666/article/details/79770278) 6 //對中間元素與目標元素進行比較 7 if(sum[mid]==v) return mid;//中間元素與目標元素相同,則退出函數,返回中間元素的位置 8 else if(sum[mid]>v) find(l,mid-1);//中間元素大於目標元素,將上界更新爲中間元素的位置-1 9 else find(mid+1,r);//中間元素小於目標元素,將下界更新爲中間元素的位置+1 10 }
2.二分答案blog
思路:當遇到求極值的問題時,若是該題目的答案具備可二分性,咱們一樣能夠用二分法來解決。依舊用l來存儲下界,用r來存儲上界,隨後用驗證函數check()來判斷l與r的中間值做爲答案是否可行,並不斷更新上界和下界,有着極高的效率,通常就是求最大的最小,最小的最大。io
代碼:class
1 //這裏以求最大值爲例 2 void find(int l,int r) 3 { 4 if(l>r) return;//當上界大於下界時,就退出函數 5 int mid=(l+r)>>1;//mid即爲l與r的中間值 6 //用驗證函數check()來判斷l與r的中間值做爲答案是否可行,其中check()函數請視題目狀況自行編寫 7 if(check(mid)) ans=mid,find(mid+1,r);//若可行,則更新答案,並將下界更新爲中間元素的位置+1 8 else find(l,mid-1);//若不可行,則將上界更新爲中間元素的位置-1 9 10 }