【備戰NOIP】[算法總結] 二分查找
二分是啥?
在有序的序列中進行折半查找,可以做到log n的時間查詢。
咋二分?
將n個元素分成大致相等的兩部分,取a[mid]與x做比較
如果x = a[n/2],則找到x,算法中止
如果x < a[n/2],則只要在數組a的左半部分繼續搜索x
如果x > a[n/2],則只要在數組a的右半部分搜索x
基本代碼實現
查找x在a數組中的位置 O(log n)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std;5 int n = 6, x, a[7] = {2, 5, 9, 10, 18, 21}; 6 int main() 7 { 8 scanf("%d", &x); 9 int left = 1, right = n, mid; 10 while(left <= right) 11 { 12 mid = (left + right) / 2; 13 if(a[mid] == x) 14 break; 15 else if(a[mid] > x)16 right = mid - 1; 17 else 18 left = mid + 1; 19 } 20 printf("the position of x : %d", mid); 21 return 0; 22 }
具體應用方法
在答案可能的範圍(區間)內二分枚舉
期間檢查所枚舉的答案是否符合題意
可以將最優性問題(直接求解,相對較難)轉化為可行性問題(枚舉答案是否可行,相對容易)
http://www.cnblogs.com/luoxn28/p/5767571.html 引用一位大牛的博客,變種說的很詳細
二分查找變種較多,不過它們的“套路”是一樣的,以上代碼就是其套路,如何快速寫出二分查找的代碼,只需按照以下步驟即可:
1 首先判斷出是返回left,還是返回right
因為我們知道最後跳出while (left <= right)循環條件是right < left,且right = left - 1。最後right和left一定是卡在"邊界值"的左右兩邊,如果是比較值為key,查找小於等於(或者是小於)key的元素,則邊界值就是等於key的所有元素的最左邊那個,其實應該返回left。
以數組{1, 2, 3, 3, 4, 5}為例,如果需要查找第一個等於或者小於3的元素下標,我們比較的key值是3,則最後left和right需要滿足以下條件:
我們比較的key值是3,所以此時我們需要返回left。
2 判斷出比較符號
int mid = (left + right) / 2; if (array[mid] ? key) { //... right = xxx; } else { // ... left = xxx; }
也就是這裏的 if (array[mid] ? key) 中的判斷符號,結合步驟1和給出的條件,如果是查找小於等於key的元素,則知道應該使用判斷符號>=,因為是要返回left,所以如果array[mid]等於或者大於key,就應該使用>=,以下是完整代碼
// 查找小於等於key的元素 int mid = (left + right) / 2; if (array[mid] >= key) { right = mid - 1; } else { left = mid + 1; }
算法的關鍵
如何去檢驗當前答案是否符合題目條件(check函數)
常見方法:
窮舉、貪心、搜索、動規、圖論、數據結構等
【備戰NOIP】[算法總結] 二分查找