1. 程式人生 > >【備戰NOIP】[算法總結] 二分查找

【備戰NOIP】[算法總結] 二分查找

blog urn while 容易 lba ges 性問題 貪心 width

二分是啥?

在有序的序列中進行折半查找,可以做到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】[算法總結] 二分查找