相信很多人對二分法是又愛又恨,愛是在於它思想簡單,效率確實高, 恨是恨在為什麼總是寫不對呢
二分查詢涉及的很多的邊界條件,邏輯比較簡單,就是寫不好
甚至有的同學乾脆把二分法背來了得了
其實背過的同學應該會有體會,硬背二分法,過一段時間依然會寫錯
例如 迴圈中到底是 小於 還是 小於等於, 到底是+1 呢,還是要-1呢
這是為什麼呢,主要是我們對區間的定義沒有想清楚,這就是我們的不變數
我們要在二分查詢的過程中,保持不變數,這也就是迴圈不變數 (感興趣的同學可以查一查)
題目是leetcode編號35的面試題. 搜尋插入位置
這道題目,我們要在陣列中插入目標值,無非是這四種情況
這四種情況確認清楚了,我們就可以嘗試解題了
暴力解法思路很直接,就是for迴圈遍歷一下,時間複雜度是o(n)
既然暴力解法的時間複雜度是on,我們就要嘗試一下使用二分查詢法。
大家注意這道題目的前提是陣列是有序陣列,這也是使用二分查詢的基礎條件
以後大家只要看到面試題裡給出的陣列是有序陣列,都可以想一想是否可以使用二分法。
同時題目還強調陣列中無重複元素,因為一旦有重複元素,使用二分查詢法返回的元素下表可能不是唯一的。
下圖來闡述一下二分法的大體思路,例如在這個陣列中,我們使用二分法尋找元素為5的位置,並返回其下標,如下圖
開始左邊界為0,右邊界下表為7,那麼中間位置下表是3, arr[3] > 5
左區間為我們下一步的查詢範圍,
左邊界為0,右邊界為2,中間位置下表為1 arr[1] < 5
右區間為我們下一步的查詢範圍
左邊界2,右邊界2,a[2] == 5,
返回下表2。
接下來呢我們來看一下二分法具體實現
我們定義 target 是在乙個在左閉右閉的區間裡,也就是[left, right]
這就決定了我們 這個二分法的**如何去寫,大家看如下**
class solution else if (nums[middle] < target) else
}// 分別處理如下四種情況
// 目標值在陣列所有元素之前,此時區間為[0, -1],所以return right + 1
// 目標值等於陣列中某乙個元素 return middle;
// 目標值插入陣列中的位置,一定是我們查詢的範圍 [left, right]之後,return right + 1
// 目標值在陣列所有元素之後的情況,也是我們查詢的範圍 [left, right]之後, return right + 1
return right + 1;}};
時間複雜度:o(logn)
時間複雜度:o(1)
效率如下:
如果說我們定義 target 是在乙個在左閉右開的區間裡,也就是[left, right)
那麼二分法的邊界處理方式則截然不同。
不變數是[left, right)的區間,如下**可以看出是如何在迴圈中堅持不變數的。
class solution else if (nums[middle] < target) else
}// 分別處理如下四種情況
// 目標值在陣列所有元素之前,此時區間為 [0,0),所以可以return right
// 目標值等於陣列中某乙個元素 return middle
// 目標值插入陣列中的位置 [left, right) ,return right 即可
// 目標值在陣列所有元素之後的情況 [left, right),return right 即可
return right;}};
時間複雜度:o(logn)
時間複雜度:o(1)
從上面兩種二分法的**中,我們可以看到是如何處理二分查詢過程中的邊界情況
很多同學二分寫不好,就是因為邊界總是不知道 該是<= 還是< 呢,
是 right = middle - 1呢 還是 right = middle呢
這都是因為沒有意識到去區間的定義,區間的定義就是我們的不變數
在二分部查詢的過程只要遵循著區間的定義也就是這個不變數
我們就可以很輕鬆的寫出二分法
以上講解大家應該對二分法中迴圈不變數有乙個直觀的感受
理解的查詢區間的定義(不變數),然後在二分迴圈中遇到了不知該如何處理的邊界條件的時候
就去想一下 我們區間的定義,這樣就知道邊界條件應該如何去寫了
通過這次講解希望幫助大家可以徹底理解二分法!
簡單遞迴 二分法查詢
題目描述 設有n個數已經按從大到小的順序排列,現在輸入x,判斷它是否在這n個數中,如果存在則輸出 yes 否則輸出 no 題目分析 該問題屬於資料的查詢問題,資料查詢有多種方法,通常方法是 順序查詢和二分查詢,當n個數排好序時,用二分查詢方法速度大大加快。二分查詢演算法 1 設有n個數,存放在a陣列...
二分法的簡單拓展
高中數學也好,初中數學也好,老師都講過二分法,這類題目多多少少也做過。比如計算根號2的值等等。計算根號2的值 近似的 思想還是二分法 計算根號2的近似值 const double eps 1e 5 doublef double x double calsort return left int mai...
leetcode162為什麼能用二分法求解
這道題。我第一遍沒做出來。參看了一些題解後,感覺它們大部分都沒講明白這道題為什麼可以用二分法。所以這裡就把我的思考分享出來吧。首先,我們需要注意題目的三個條件 1 限定了nums i nums i 1 這為我們排除了出現連續相等子串行的情況。2 num 1 和num n 的值為負無窮,那麼陣列在左邊...