国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

還不會(huì)二分查找?看這一篇就夠了

這篇具有很好參考價(jià)值的文章主要介紹了還不會(huì)二分查找?看這一篇就夠了。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

一、整數(shù)二分

二分查找分為整數(shù)二分和浮點(diǎn)數(shù)二分,一般所說的二分查找都是指整數(shù)二分。

1.1 二分查找模板

滿足單調(diào)性的數(shù)組一定可以使用二分查找,但可以使用二分查找的數(shù)組不一定需要滿足單調(diào)性。

不妨假設(shè)我們找到了條件 C 1 C_1 C1?,它和它的對(duì)立條件 C 2 C_2 C2? 能夠?qū)?shù)組 a a a 一分為二,如下圖所示:

還不會(huì)二分查找?看這一篇就夠了,DSA,# AcWing,c++,二分查找,算法

因?yàn)? C 1 C_1 C1? C 2 C_2 C2? 互為對(duì)立,故總有 C 1 ∪ C 2 ≡ True , ?? C 1 ∩ C 2 ≡ False C_1\cup C_2\equiv \text{True},\;C_1\cap C_2\equiv \text{False} C1?C2?True,C1?C2?False(用C++語言描述,就是 c1 || !c1 總是為真,c1 && !c1 總是為假)。換句話說, ? ? x ∈ a \forall \,x\in a ?xa, x x x 至少滿足 C 1 C_1 C1? C 2 C_2 C2? 中的一個(gè),且 x x x 不會(huì)同時(shí)滿足 C 1 C_1 C1? C 2 C_2 C2?。

觀察上圖可以發(fā)現(xiàn),索引 3 3 3 和索引 4 4 4 這兩個(gè)位置都可以作為 C 1 C_1 C1? C 2 C_2 C2? 的分界點(diǎn)。其中,索引 3 3 3 是紅色區(qū)域的右邊界,索引 4 4 4 是綠色區(qū)域的左邊界。而我們接下來要討論的二分查找模板就是用來尋找 C 1 C_1 C1? C 2 C_2 C2? 的分界點(diǎn)的。

1.1.1 尋找右邊界的二分查找

前面說過, C 1 C_1 C1? C 2 C_2 C2? 的分界點(diǎn)一共有兩個(gè),因此我們的整數(shù)二分查找模板也有兩個(gè)。一個(gè)用來查找右邊界(即左側(cè)的分界點(diǎn),對(duì)應(yīng)索引 3 3 3),一個(gè)用來查找左邊界(即右側(cè)的分界點(diǎn),對(duì)應(yīng)索引 4 4 4)。這里首先介紹查找右邊界的模板。

因?yàn)椴檎业氖?strong>紅色區(qū)域的右邊界,所以先定義一個(gè)函數(shù) check(i),其中參數(shù) i i i 是索引。當(dāng) i i i 位于紅色區(qū)域,即 0 ≤ i ≤ 3 0\leq i \leq 3 0i3 時(shí),check(i) 為真;當(dāng) i i i 位于綠色區(qū)域,即 4 ≤ i ≤ 7 4\leq i \leq 7 4i7 時(shí),check(i) 為假。

初始時(shí)設(shè)置左右兩個(gè)指針分別位于數(shù)組的左右兩端,每次循環(huán)時(shí)計(jì)算 m i d = l + r 2 mid=\frac{l+r}{2} mid=2l+r?(至于 m i d mid mid 到底取多少稍后會(huì)說),然后判斷 check(mid) 的值(為實(shí)現(xiàn)二分查找,我們需要確保每次縮小區(qū)間時(shí)答案都落在區(qū)間內(nèi)。這樣一來,當(dāng)最終 l == r 時(shí),l 就是我們需要的答案)。如果 check(mid) 為真,說明 m i d mid mid 位于紅色區(qū)域,且 m i d mid mid 有可能就是右邊界,因此接下來令 l = m i d l=mid l=mid 來縮小查找范圍(因?yàn)槲覀円WC縮小后的區(qū)間仍然包含答案);如果 check(mid) 為假,說明 m i d mid mid 位于綠色區(qū)域,且 m i d mid mid 必不可能是紅色區(qū)域的右邊界,因?yàn)? m i d mid mid 最多是索引 4 4 4,因此令 r = m i d ? 1 r=mid-1 r=mid?1 來縮小查找范圍。

接下來重點(diǎn)關(guān)注 m i d mid mid 到底該取多少。如果 m i d = l + r 2 mid=\frac{l+r}{2} mid=2l+r?,其中的除法代表整除,在某一輪循環(huán)出現(xiàn)了 r ? l = 1 r-l=1 r?l=1,則 m i d = 2 l + 1 2 = l mid=\frac{2l+1}{2}=l mid=22l+1?=l。若 check(mid) 為真,則更新后的區(qū)間仍然為 [ l , r ] [l,r] [l,r],這就會(huì)導(dǎo)致無限循環(huán)。事實(shí)上,只需要取 m i d = l + r + 1 2 mid=\frac{l+r+1}{2} mid=2l+r+1?,若 check(mid) 為真,則 m i d = r mid=r mid=r,更新后的區(qū)間為 [ r , r ] [r,r] [r,r],循環(huán)結(jié)束。若 check(mid) 為假,則更新后的區(qū)間為 [ l , l ] [l,l] [l,l],循環(huán)結(jié)束。

尋找右邊界的二分查找模板:

int right_bound(int l, int r) {
    while (l < r) {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

1.1.2 尋找左邊界的二分查找

類似1.1.1節(jié)中的分析,因?yàn)椴檎业氖?strong>綠色區(qū)域的左邊界,所以先定義一個(gè)函數(shù) check(i),其中參數(shù) i i i 是索引。當(dāng) i i i 位于綠色區(qū)域,即 4 ≤ i ≤ 7 4\leq i \leq 7 4i7 時(shí),check(i) 為真;當(dāng) i i i 位于紅色區(qū)域,即 0 ≤ i ≤ 3 0\leq i \leq 3 0i3 時(shí),check(i) 為假。

初始時(shí)設(shè)置左右兩個(gè)指針分別位于數(shù)組的左右兩端,每次循環(huán)時(shí)計(jì)算 m i d = l + r 2 mid=\frac{l+r}{2} mid=2l+r?(至于 m i d mid mid 到底取多少稍后會(huì)說),然后判斷 check(mid) 的值。如果 check(mid) 為真,說明 m i d mid mid 位于綠色區(qū)域,且 m i d mid mid 有可能就是左邊界,因此接下來令 r = m i d r=mid r=mid 來縮小查找范圍;如果 check(mid) 為假,說明 m i d mid mid 位于紅色區(qū)域,且 m i d mid mid 必不可能是綠色區(qū)域的左邊界,因?yàn)? m i d mid mid 最多是索引 3 3 3,因此令 l = m i d + 1 l=mid+1 l=mid+1 來縮小查找范圍。

接下來重點(diǎn)關(guān)注 m i d mid mid 到底該取多少。如果 m i d = l + r 2 mid=\frac{l+r}{2} mid=2l+r?,其中的除法代表整除,在某一輪循環(huán)出現(xiàn)了 r ? l = 1 r-l=1 r?l=1,則 m i d = 2 l + 1 2 = l mid=\frac{2l+1}{2}=l mid=22l+1?=l。若 check(mid) 為真,則更新后的區(qū)間為 [ l , l ] [l,l] [l,l],循環(huán)結(jié)束。若 check(mid) 為假,則更新后的區(qū)間為 [ r , r ] [r,r] [r,r],循環(huán)結(jié)束。綜上所述, m i d mid mid l + r 2 \frac{l+r}{2} 2l+r? 即可。

尋找左邊界的二分查找模板:

int left_bound(int l, int r) {
    while (l < r) {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
    return l;
}

1.2 應(yīng)用:尋找元素的起始位置和終止位置

原題鏈接:AcWing 789. 數(shù)的范圍

a = [1, 3, 3, 3, 4] 為例,數(shù)字 3 3 3 的起始位置和終止位置分別是 1 1 1 3 3 3(索引)。如何利用1.1節(jié)中的模板來完成此題呢?

現(xiàn)對(duì)數(shù)組 a a a 作出劃分,若令 C 1 : a [ i ] < x , ?? C 2 : a [ i ] ≥ x C_1:a[i]<x,\; C_2:a[i]\geq x C1?:a[i]<x,C2?:a[i]x(注意必須保證 C 1 , C 2 C_1,C_2 C1?,C2? 互為對(duì)立),則求 x x x 的起始位置便轉(zhuǎn)化成了求 C 2 C_2 C2? 區(qū)域的左邊界。若令 C 1 : a [ i ] ≤ x , ?? C 2 : a [ i ] > x C_1:a[i]\leq x,\; C_2:a[i]> x C1?:a[i]x,C2?:a[i]>x,則求 x x x 的終止位置便轉(zhuǎn)化成了求 C 1 C_1 C1? 區(qū)域的右邊界。

在求 C 2 C_2 C2? 區(qū)域的左邊界時(shí),check(mid) 即為 a[mid] >= x。在求 C 1 C_1 C1? 區(qū)域的右邊界時(shí),check(mid) 即為 a[mid] <= x。

AC代碼如下:

#include <iostream>

using namespace std;

const int N = 1e5 + 10;

int a[N];

int left_bound(int l, int r, int x) {
    while (l < r) {
        int mid = l + r >> 1;
        if (a[mid] >= x) r = mid;
        else l = mid + 1;
    }
    return l;
}

int right_bound(int l, int r, int x) {
    while (l < r) {
        int mid = l + r + 1 >> 1;
        if (a[mid] <= x) l = mid;
        else r = mid - 1;
    }
    return l;
}

int main() {
    int n, q;
    cin >> n >> q;
    for (int i = 0; i < n; i++) cin >> a[i];

    while (q--) {
        int k;
        cin >> k;
        int begin = left_bound(0, n - 1, k);
        if (a[begin] != k) cout << "-1 -1" << endl;
        else cout << begin << " " << right_bound(0, n - 1, k) << endl;
    }

    return 0;
}

二、浮點(diǎn)數(shù)二分

2.1 浮點(diǎn)數(shù)二分模板

相比整數(shù)二分,浮點(diǎn)數(shù)二分就要簡單許多了,因?yàn)楦↑c(diǎn)數(shù)二分不涉及到邊界問題。

浮點(diǎn)數(shù)二分通常用來求某個(gè)數(shù) x x x 的近似值 x x x 不易直接求得,例如 x = 2 x=\sqrt{2} x=2 ? 等)。由于此時(shí)左右兩個(gè)指針也均為浮點(diǎn)數(shù),所以我們不能直接判斷 l == r,而是判斷 r - l 是否小于預(yù)先設(shè)定的精度。

模板如下:

double fbsearch(double l, double r, double eps) {
    while (r - l > eps) {
        double mid = (l + r) / 2;
        if (check(mid)) r = mid;
        else l = mid;
    }
    return l;
}

一些注意事項(xiàng):

  • 若要求精確到小數(shù)點(diǎn)后 k k k 位,則 e p s eps eps 1 0 ? ( k + 2 ) 10^{-(k+2)} 10?(k+2);
  • m i d ≥ x mid\geq x midx,則 check(mid) 為真,否則為假。

2.2 應(yīng)用:數(shù)的三次方根

原題鏈接:AcWing 790. 數(shù)的三次方根

注意到當(dāng) ∣ x ∣ < 1 |x|<1 x<1 時(shí),有 ∣ x 1 / 3 ∣ > ∣ x ∣ |x^{1/3}|>|x| x1/3>x,故選取 l , r l,r l,r 時(shí)一定要謹(jǐn)慎。

因?yàn)? 1000 0 1 / 3 < 22 10000^{1/3}<22 100001/3<22,所以這里取 l = ? 22 , ? r = 22 l=-22,\,r=22 l=?22,r=22 即可。

#include <iostream>

using namespace std;

double x;

double fbsearch(double l, double r, double eps) {
    while (r - l > eps) {
        double mid = (l + r) / 2;
        if (mid * mid * mid >= x) r = mid;
        else l = mid;
    }
    return l;
}

int main() {
    cin >> x;
    printf("%lf", fbsearch(-22, 22, 1e-8));
    return 0;
}

三、使用STL進(jìn)行二分查找

3.1 std::binary_search

template< class ForwardIt, class T >
bool binary_search( ForwardIt first, ForwardIt last, const T& value );

該函數(shù)用來檢查 [first, last) 區(qū)間內(nèi)(該區(qū)間已排序)是否有數(shù)字等于 value,如果有返回 true,否則返回 false

3.2 std::lower_bound

template< class ForwardIt, class T >
ForwardIt lower_bound( ForwardIt first, ForwardIt last, const T& value );

該函數(shù)用來返回 [first, last) 區(qū)間內(nèi)(該區(qū)間已排序)首個(gè)大于等于 value 的元素的迭代器,如果找不到這種元素則返回 last

3.3 std::upper_bound

template< class ForwardIt, class T >
ForwardIt upper_bound( ForwardIt first, ForwardIt last, const T& value );

該函數(shù)用來返回 [first, last) 區(qū)間內(nèi)(該區(qū)間已排序)首個(gè)大于 value 的元素的迭代器,如果找不到這種元素則返回 last。

3.4 std::equal_range

template< class ForwardIt, class T >
std::pair<ForwardIt, ForwardIt>
    equal_range( ForwardIt first, ForwardIt last, const T& value );

該函數(shù)用來返回 [first, last) 區(qū)間內(nèi)(該區(qū)間已排序)所有等于 value 的元素的「范圍」。

「范圍」實(shí)際上是由兩個(gè)迭代器構(gòu)成的 pair。pair 中的第一個(gè)元素是 std::lower_bound 的返回值,pair 中的第二個(gè)元素是 std::upper_bound 的返回值。


接下來我們用STL來簡化1.2節(jié)中的代碼。

注意到對(duì)于數(shù)組而言,其迭代器就是指針,因此我們可以通過將返回的迭代器與數(shù)組名作差來得到迭代器所指向的元素的下標(biāo)。

簡化后的代碼如下:

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1e5 + 10;

int a[N];

int main() {
    int n, q;
    cin >> n >> q;
    for (int i = 0; i < n; i++) cin >> a[i];

    while (q--) {
        int k;
        cin >> k;
        auto p = equal_range(a, a + n, k);
        if (*p.first != k) cout << "-1 -1" << endl;
        else cout << p.first - a << " " << p.second - a - 1 << endl;
    }

    return 0;
}

References

[1] https://www.acwing.com/activity/content/punch_the_clock/11/
[2] https://www.acwing.com/blog/content/31/
[3] https://zh.cppreference.com/w/cpp/algorithm/lower_bound文章來源地址http://www.zghlxwxcb.cn/news/detail-804568.html

到了這里,關(guān)于還不會(huì)二分查找?看這一篇就夠了的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • ElasticSearch常見用法,看這一篇就夠了

    ElasticSearch常見用法,看這一篇就夠了

    2024送書福利正式起航 關(guān)注「哪吒編程」,提升Java技能 文末送3本《一本書講透Elasticsearch:原理、進(jìn)階與工程實(shí)踐》 大家好,我是哪吒。 ElasticSearch是一款由Java開發(fā)的開源搜索引擎,它以其出色的實(shí)時(shí)搜索、穩(wěn)定可靠、快速安裝和方便使用的特性,在Java開發(fā)社區(qū)中贏得了廣

    2024年03月19日
    瀏覽(94)
  • 超圖(HyperGraph)學(xué)習(xí),看這一篇就夠了

    超圖(HyperGraph)學(xué)習(xí),看這一篇就夠了

    最近事多,好久沒更新了,隨便寫寫(Ctrl+V)點(diǎn) 一、超圖定義 通常圖論中的圖,一條edge只能連接2個(gè)vertex,在超圖中,不限量 如何理解呢,就用我正在做的KT問題來看:7道題目-7個(gè)頂點(diǎn);4種概念-4條超邊,其中第1,2,3題都是考察概念1的,則構(gòu)建一個(gè)包含了這仨的超邊,以此類

    2024年02月02日
    瀏覽(27)
  • SourceTree使用看這一篇就夠了

    SourceTree使用看這一篇就夠了

    ?你夢想有一天成為git大師,然而面對(duì)復(fù)雜的git命令,你感覺TMD這我能記得住嗎?你曾經(jīng)羨慕從命令行敲git命令,才會(huì)更加炫酷,然而時(shí)間一長,TMD命令我有忘了。那么今天我介紹的這款工具會(huì)讓你從git命令中解救出來,這就是git可視化工具SourcTree。 事實(shí)上Git的功能十分強(qiáng)大

    2024年02月08日
    瀏覽(23)
  • Docker Volume 看這一篇就夠了

    Docker Volume 看這一篇就夠了

    默認(rèn)情況下,在容器內(nèi)創(chuàng)建的所有文件都存儲(chǔ)在可寫容器層上。這意味著: 當(dāng)該容器不再存在時(shí),數(shù)據(jù)不會(huì)持續(xù)存在,并且如果另一個(gè)進(jìn)程需要數(shù)據(jù),則可能很難將數(shù)據(jù)從容器中取出。 容器的可寫層與運(yùn)行容器的主機(jī)緊密耦合。您無法輕松地將數(shù)據(jù)移動(dòng)到其他地方。 寫入容

    2024年02月02日
    瀏覽(106)
  • CAS自旋鎖,看這一篇就夠了

    前序 時(shí)隔多年,杰倫終于出了新專輯,《最偉大的作品》讓我們穿越到1920年,見到了馬格利特的綠蘋果、大利的超現(xiàn)實(shí)、常玉畫的大腿、莫奈的睡蓮、徐志摩的詩… 他說“最偉大的作品”并不是自己的歌,而是這個(gè)世界上最偉大的藝術(shù)作品們。 為什么要寫CAS自旋鎖呢?最近

    2023年04月08日
    瀏覽(19)
  • 了解5G安全標(biāo)準(zhǔn),看這一篇就夠了

    了解5G安全標(biāo)準(zhǔn),看這一篇就夠了

    隨著移動(dòng)通信系統(tǒng)在社會(huì)生活中的使用越來越廣泛,特別是5G進(jìn)一步以企業(yè)級(jí)應(yīng)用作為核心應(yīng)用場景,安全成為了包括5G在內(nèi)的移動(dòng)通信系統(tǒng)不可忽視的因素。本文梳理了全球主流移動(dòng)通信標(biāo)準(zhǔn)化組織在安全方面的標(biāo)準(zhǔn)制定,從而可以快速了解5G協(xié)議層面對(duì)信息安全的考量。原

    2024年02月05日
    瀏覽(27)
  • MSP432速成教程(看這一篇就夠了)

    MSP432速成教程(看這一篇就夠了)

    (一)GPIO輸出 打開芯片數(shù)據(jù)手冊(msp432p401r)第17頁的表詳細(xì)描述了對(duì)應(yīng)引腳的GPIO功能 1.庫函數(shù) 配置GPIO模式: 設(shè)置高低電平 配置驅(qū)動(dòng)強(qiáng)度 只有P2.0、P2.1、P2.2、P2.3引腳可以配置為高驅(qū)動(dòng)程度 This I/O can be configured for high drive operation with up to 20-mA drive capability. 此I/O可配置為高達(dá)

    2024年02月13日
    瀏覽(28)
  • C++異常處理詳解 看這一篇就夠了

    C++異常處理詳解 看這一篇就夠了

    在程序運(yùn)行的過程中,我們不可能保證我們的程序百分百不出現(xiàn)異常和錯(cuò)誤,那么出現(xiàn)異常時(shí)該怎么報(bào)錯(cuò),讓我們知道是哪個(gè)地方錯(cuò)誤了呢? C++中就提供了異常處理的機(jī)制。 throw : 當(dāng)問題出現(xiàn)時(shí),程序會(huì)拋出一個(gè)異常。這是通過使用 throw 來完成的。 catch : 在您想要處理

    2024年02月14日
    瀏覽(30)
  • Java迭代器詳解,看這一篇就夠了

    Java迭代器詳解,看這一篇就夠了

    迭代器 是屬于 設(shè)計(jì)模式 之一, 迭代器模式 提供了一種方法來順序訪問一個(gè)聚合對(duì)象中各個(gè)元素,而不保留該對(duì)象的內(nèi)部表示。 1) Iterator對(duì)象 稱為 迭代器 ,主要用于遍歷 Collection集合 中的元素。 2)所有實(shí)現(xiàn)了 Collection接口 的集合類都有一個(gè) iterator() 方法,用以返回一個(gè)

    2024年02月02日
    瀏覽(21)
  • 關(guān)于Tacotron2看這一篇就夠了

    關(guān)于Tacotron2看這一篇就夠了

    文章來源 [1712.05884] NATURAL TTS SYNTHESIS BY CONDITIONING WAVENET ON MEL SPECTROGRAM PREDICTIONS 參考博客 聲譜預(yù)測網(wǎng)絡(luò)(Tacotron2) Tacotron2 論文 + 代碼詳解 Tacotron2講解 論文閱讀 Tacotron2 Tacotron2 模型詳解 Tacotron2-Details 簡介: The system is composed of a recurrent sequence-to-sequence feature prediction network that m

    2024年02月09日
    瀏覽(19)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包