lower_bound以及upper_bound
STL中實現了這兩個演算法,但是代碼看起來非常晦澀,如果要快速寫出這兩個演算法的話,參照STL的實現,恐怕會非常費勁.這裡,我提供一種非常簡潔的實現.
代碼僅供參考. lower_bound
給定一個有序數組 vals, 尋找 vals 中第一個為 k 的值的下標,沒有找到的話,返回 -1.
舉個栗子, vals = [0, 1, 1, 1, 2, 3], 那麼 lower_bound應該返回 1.
下面的演算法的思想很簡單,簡單的二分法尋找,二分尋找演算法的關鍵在於,每一次迭代,尋找的範圍都必須縮小,也就是每一次要麼是 begin 向前,要麼是 end 後退,如果範圍不縮小的話,很有可能出現無限迭代的情況.
尋找的時候還有一個特別要注意的地方,那就是如果 vals[mid] == k 的話, 如果是一般的二分尋找演算法的話,此刻返回即可,但是我們要找的是第一個 k, 此刻將end 要更新為 mid - 1, end無非兩種可能,要麼指向一個小於 k 的數, 這樣的話, vals[mid] < k 總是成立,再加上 while 終止的條件, begin 最終會等於 end + 1 .
另外一種情況是 end 指向的數等於 k, 這樣的話, end 在接下來的迭代中再次被更新為 mid - 1, 一直到 end 指向一個不等於 k 的數.
int lower_bound(vector<int>& vals, int k) { /* 尋找第一個k */ int begin = 0, end = vals.size() - 1; while (begin <= end) { /* begin不斷向end逼近 */ int mid = (begin + end) / 2; if (vals[mid] < k) { begin = mid + 1; } else if (vals[mid] > k) { end = mid - 1; } else { /* vals[mid] == k */ end = mid - 1; } } if (begin >= vals.size()) return -1; return vals[begin] == k ? begin : -1;}
upper_bound
upper_bound 函數用於尋找有序數組 vals 中最後一個等於 k 的值的下標(從左向右掃描), 找不到的話,返回 -1.
下面的代碼和上面的稍微有一點不同,當 vals[mid] == k 的時候, begin 會被更新為 mid + 1, 此時的 begin 指向的數無非兩種可能, 一種不等於 k, 這樣的話,接下來的迭代中 vals[mid] > k 總是成立的, 加上 while 的遞迴終止條件 begin <= end, end 最終會等於 begin - 1.
另外一種情況是 begin 指向的數等於 k, 同上面一樣的道理,接下來的迭代中, begin 會繼續向前靠攏.
int upper_bound(vector<int>& vals, int k) { /* 尋找最後一個k */ int begin = 0, end = vals.size() - 1; while (begin <= end) { int mid = (begin + end) / 2; if (vals[mid] < k) { begin = mid + 1; } else if (vals[mid] > k) { end = mid - 1; } else { /* vals[mid] == k */ begin = mid + 1; } } if (end < 0) return -1; return vals[end] == k ? end : -1; }