二分法(二分查找,二分答案)

二分是一個經常使用的小技巧,能夠將本來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 }
相關文章
相關標籤/搜索