BackgroundService 大佬教的好
有人說,90%的程式設計師都手寫不出正確的二分查詢
沒錯,我就是那90%
c++的標準庫裡只提供了binary_search(),lower_bound(),upper_bound()三個函式,缺點就是,只能在陣列或者vector這樣的線性資料結構上二分
所以就需要整理一下二分的用法和程式碼
1,binary_search(arr[],arr[]+size,key,cmp)
功能:找到正好等於key的元素,成功則返回位置,否則返回陣列末尾指標
注意,給出的最後一個引數是比較函式的指標,如果不給出,預設呼叫標準庫中的less()函式,其實就是小於號。
這個是最好寫的,不需要考慮左右邊界或者失配的問題
(偽)程式碼:
int binary_search(arr[],arr[]+size,key,cmp) { int left = 0; int right = nums.length - 1; while(left <= right) { int mid = (right + left) / 2; if(equal(arr[mid],key)) return arr[]+mid; else if (less(nums[mid],target)) left = mid + 1; else right = mid - 1; } return arr[]+size; }
2,lower_bound(arr[],arr[]+size,key,cmp)
這個函式的功能是找出第一個大於等於key的值,可以簡記為左邊界,和上一個函式不同的是,除非key值大於全部陣列中的值,才會返回arr[]+size,否則一定會返回一個有效值。
(偽)程式碼:
int lower_bound(arr[],arr[]+size,key,cmp){ int left = 0; int right = size-1; while (left <= right) { int mid = (left + right) / 2; if(less(arr[mid],key)){ left = mid + 1; } else{ right = mid - 1; } } return arr[]+left; }
注意,這個函式就比上一個難寫很多,比如left,right為什麼要小於等於,最後要返回的是left還是right,等等
3,upper_bound(arr[],arr[]+size,key,cmp)
這個函式的功能是找出大於key的第一個值的位置,簡稱右邊界
int upper_bound(arr[],arr[]+size,key,cmp){ int left = 0; int right = size-1; //查詢第一個大於key的元素 while (left <= right) { int mid = (left + right) / 2; if (less(key,a[mid])) { right = mid - 1; } else { left = mid + 1; } } return arr[]+left; }
這個函式常用於給整數開平方根,因為大於key的第一個值,減去1,就是小於等於key的最後一個值
涉及到給整數開平方根或者類似的操作的,一定記得用二分,不要自作聰明求解析解,然後轉換成double,在cmath庫裡的函式求解,再轉換回來,絕對不要!
我是不會告訴你我被昨晚的atcoder arc的B題卡了一個多小時的,天知道,1e18的資料範圍,他是怎麼想到構造出卡掉double+sqrt的資料的
參考資料: