二分查詢與二分答案
阿新 • • 發佈:2020-07-18
前言
注意:每個人有每個人的寫法。
這個重要且基礎的點,虎哥和老姚都以為對方講了,可誰都沒講。並且老姚的二分答案我看不懂,然後借鑑了oi-wiki好理解的。
由於老姚的mid+1的不確定性,我是搞不明白,請看到的學長解釋一下老姚的。
二分查詢
二分搜尋,也稱折半搜尋、二分查詢,是用來在一個有序陣列中查詢某一元素的演算法。
它每次考察陣列當前部分的中間元素,如果中間元素剛好是要找的,就結束搜尋過程;如果中間元素小於所查詢的值,那麼左側的只會更小,不會有所查詢的元素,只需要到右側去找就好了;如果中間元素大於所查詢的值,同理,右側的只會更大而不會有所查詢的元素,所以只需要到左側去找。
code:
int Search (int l,int r,int x) { int mid; while(l<=r) { mid=l+((r-l)>>1); if(a[mid]<x) mid=l-1; else if(a[mid]>x) mid=r+1; else if(a[mid]==x) return mid; } return -1; }
注意,這裡的有序是廣義的有序,如果一個數組中的左側或者右側都滿足某一種條件,而另一側都不滿足這種條件,也可以看作是一種有序(如果把滿足條件看做1
,不滿足看做0
,然後再加一個Check(mid))。所以,二分搜尋法可以用來查詢滿足某種條件的最大(最小)的值,也就是二分答案。
二分答案
要想使用二分搜尋法來解這種「最大值最小化」的題目(wiki上的)
需要滿足以下三個條件:
1.答案在一個固定區間內;
2.可能查詢一個符合條件的值不是很容易,但是要求能比較容易地判斷某個值是否是符合條件的;
3.可行解對於區間滿足一定的單調性。換言之,如果x
是符合條件的,那麼有x+1
或者x-1
也符合條件。(這樣下來就滿足了上面提到的單調性)
左側合法的最大值
code:
int Search(int l,int r)
{
++r;//左閉右開
int mid;
while(l+1<r)//不相鄰
{
mid=l+((r-l)>>1);
if(Check(mid)) l=mid;//l一直是合法的
else r=mid;
}
return l;//返回合法
}
為什麼左閉右開
因為搜到最後,會這樣:
合法 | 合法 | 合法 | 合法 | 非法 | 非法 | 非法 |
---|---|---|---|---|---|---|
最小值 | ··· | l | mid | r | ··· | 最大值 |
或
合法 | 合法 | 合法 | 非法 | 非法 | 非法 | 非法 |
---|---|---|---|---|---|---|
最小值 | ··· | l | mid | r | ··· | 最大值 |
然後會
合法 | 合法 | 合法 | 非法 | 非法 | 非法 |
---|---|---|---|---|---|
最小值 | ··· | l\mid | r | ··· | 最大值 |
或
合法 | 合法 | 合法 | 非法 | 非法 | 非法 |
---|---|---|---|---|---|
最小值 | ··· | l | r\mid | ··· | 最大值 |
模擬是正確的,但為什麼不是左閉右閉呢?是因為如果答案是最大值,那就wa了(它會返回最大值-1)。
右側合法的最小值
code
int Search(int l,int r)
{
--l;//左開右閉
int mid;
while(l+1<r)//不相鄰
{
mid=l+((r-l)>>1);
if(Check(mid)) r=mid;//r一直是合法的
else l=mid;
}
return r;//返回合法
}
為什麼左開右閉
因為搜到最後,會這樣:
非法 | 非法 | 非法 | 非法 | 合法 | 合法 | 合法 |
---|---|---|---|---|---|---|
最小值 | ··· | l | mid | r | ··· | 最大值 |
或
非法 | 非法 | 非法 | 合法 | 合法 | 合法 | 合法 |
---|---|---|---|---|---|---|
最小值 | ··· | l | mid | r | ··· | 最大值 |
然後會
非法 | 非法 | 非法 | 合法 | 合法 | 合法 |
---|---|---|---|---|---|
最小值 | ··· | l\mid | r | ··· | 最大值 |
或
非法 | 非法 | 非法 | 合法 | 合法 | 合法 |
---|---|---|---|---|---|
最小值 | ··· | l | r\mid | ··· | 最大值 |
模擬是正確的,但為什麼不是左閉右閉呢?是因為如果答案是最小值,那就wa了(它會返回最小值+1)。