在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

二分查找算法如何運用?

算法與數據結構 ? 來源:labuladong ? 作者:labuladong ? 2020-10-30 09:39 ? 次閱讀

讀完本文,你可以去力扣解決:410.分割數組的最大值(Hard)

經常有讀者問我,讀了之前的爆文二分查找框架詳解之后,二分查找的算法他寫的很溜了,但僅僅局限于在數組中搜索元素,不知道底怎么在算法題里面運用二分查找技巧來優化效率。

那我先說結論,你想用二分查找技巧優化算法,首先要把 for環形式的暴力算法寫出來,如果算法中存在如下形式的 for 循環:

//func(i)是i的單調函數(遞增遞減都可以) intfunc(inti); //形如這種for循環可以用二分查找技巧優化效率 for(inti=0;i

如果func(i)函數是在i上單調的函數,一定可以使用二分查找技巧優化 for 循環。

「在i上單調的函數」是指func(i)的返回值隨著i的增加而增加,或者隨著i的增加而減小。

為什么滿足這個條件就可以使用二分查找?因為這個邏輯和「在有序數組中查找一個元素」是完全一樣的呀!

在有序數組nums中查找某一個數target,是不是最簡單二分查找形式?我們看下普通的 for 循環遍歷算法:

//nums是一個有序數組 int[]nums; //target是要搜索的元素 inttarget; //搜索target在nums中的索引 for(inti=0;i

既然nums是有序數組,你把nums[i]看做函數調用,是不是可以理解為nums在參數i上是單調的?這是不是和之前說的func(i)函數完全一樣?

當然,前文二分查找框架詳解說過,二分查找算法還有搜索左側、右側邊界的變體,怎么運用到具體算法問題中呢?

還是注意觀察 for 循環形式,只是不一定是func(i) == target作為終止條件,可能是<=或者>=的關系,這個可以根據具體的題目意思來推斷,我們實操一下力扣第 410 題「分割數組的最大值」,難度Hard:

函數簽名如下:

intsplitArray(int[]nums,intm);

這個題目有點類似前文一道經典動態規劃題目高樓扔雞蛋,題目比較繞,又是最大值又是最小值的。

簡單說,給你輸入一個數組nums和數字m,你要把nums分割成m個子數組。

肯定有不止一種分割方法,每種分割方法都會把nums分成m個子數組,這m個子數組中肯定有一個和最大的子數組對吧。

我們想要找一個分割方法,該方法分割出的最大子數組和是所有方法中最大子數組和最小的。

請你的算法返回這個分割方法對應的最大子數組和。

我滴媽呀,這個題目看了就覺得 Hard,完全沒思路,這題怎么能和二分查找算法扯上關系?

說個小插曲,快手面試有一道畫師畫畫的算法題,很難,就是以這道題為原型。當時我沒做過這道力扣題,面試有點懵,不過之前文章二分查找算法運用寫了兩道類似的比較簡單的題目,外加面試官的提示,把那道題做出來了。

面試做算法題的時候,題目一般都會要求算法的時間復雜度,如果你發現 O(NlogN) 這樣存在對數的復雜度,一般都要往二分查找的方向上靠,這也算是個小套路。

言歸正傳,如何解決這道數組分割的問題?

首先,一個拍腦袋的思路就是用回溯算法框架暴力窮舉唄,我簡單說下思路:

你不是要我把nums分割成m個子數組,然后計算巴拉巴拉又是最大又是最小的那個最值嗎?那我把所有分割方案都窮舉出來,那個最值肯定可以算出來對吧?

怎么窮舉呢?把nums分割成m個子數組,相當于在len(nums)個元素的序列中切m - 1刀,對于每兩個元素之間的間隙,我們都有兩種「選擇」,切一刀,或者不切。

你看,這不就是標準的回溯暴力窮舉思路嘛,我們根據窮舉結果去計算每種方案的最大子數組和,肯定可以算出答案。

但是回溯的缺點就是復雜度很高,我們剛才說的思路其實就是「組合」嘛,時間復雜度就是組合公式:

時間復雜度其實是非常高的,所以回溯算法不是一個好的思路,還是得上二分查找技巧,反向思考這道題。

現在題目是固定了m的值,讓我們確定一個最大子數組和;所謂反向思考就是說,我們可以反過來,限制一個最大子數組和max,來反推最大子數組和為max時,至少可以將nums分割成幾個子數組。

比如說我們可以寫這樣一個split函數:

//在每個子數組和不超過max的條件下, //計算nums至少可以分割成幾個子數組 intsplit(int[]nums,intmax);

比如說nums = [7,2,5,10],若限制max = 10,則split函數返回 3,即nums數組最少能分割成三個子數組,分別是[7,2],[5],[10]。

如果我們找到一個最小max值,滿足split(nums, max)和m相等,那么這個max值不就是符合題意的「最小的最大子數組和」嗎?

現在就簡單了,我們只要對max進行窮舉就行,那么最大子數組和max的取值范圍是什么呢?

顯然,子數組至少包含一個元素,至多包含整個數組,所以「最大」子數組和的取值范圍就是閉區間[max(nums), sum(nums)],也就是最大元素值到整個數組和之間。

那么,我們就可以寫出如下代碼:

/*主函數,計算最大子數組和*/ intsplitArray(int[]nums,intm){ intlo=getMax(nums),hi=getSum(nums); for(intmax=lo;max<=?hi;?max++)?{ ????????//?如果最大子數組和是?max, ????????//?至少可以把?nums?分割成?n?個子數組 ????????int?n?=?split(nums,?max); ????????//?為什么是?<=?不是?==?? ????????if?(n?<=?m)?{ ????????????return?max; ????????} ????} ????return?-1; } /*?輔助函數,若限制最大子數組和為?max, 計算?nums?至少可以被分割成幾個子數組?*/ int?split(int[]?nums,?int?max)?{ ????//?至少可以分割的子數組數量 ????int?count?=?1; ????//?記錄每個子數組的元素和 ????int?sum?=?0; ????for?(int?i?=?0;?i?max){ //如果當前子數組和大于max限制 //則這個子數組不能再添加元素了 count++; sum=nums[i]; }else{ //當前子數組和還沒達到max限制 //還可以添加元素 sum+=nums[i]; } } returncount; } //計算數組中的最大值 intgetMax(int[]nums){ intres=0; for(intn:nums) res=Math.max(n,res); returnres; } //計算數組元素和 intgetSum(int[]nums){ intres=0; for(intn:nums) res+=n; returnres; }

這段代碼有兩個關鍵問題:

1、對max變量的窮舉是從lo到hi即從小到大的。

這是因為我們求的是「最大子數組和」的「最小值」,且split函數的返回值有單調性,所以從小到大遍歷,第一個滿足條件的值就是「最小值」。

2、函數返回的條件是n <= m,而不是n == m。按照之前的思路,應該n == m才對吧?

其實,split函數采用了貪心的策略,計算的是max限制下至少能夠將nums分割成幾個子數組。

舉個例子,輸入nums = [2,1,1], m = 3,顯然分割方法只有一種,即每個元素都認為是一個子數組,最大子數組和為 2。

但是,我們的算法會在區間[2,4]窮舉max,當max = 2時,split會算出nums至少可以被分割成n = 2個子數組[2]和[1,1]。

當max = 3時算出n = 2,當max = 4時算出n = 1,顯然都是小于m = 3的。

所以我們不能用n == m而必須用n <= m來找到答案,因為如果你能把nums分割成 2 個子數組([2],[1,1]),那么肯定也可以分割成 3 個子數組([2],[1],[1])。

好了,現在 for 循環的暴力算法已經寫完了,但是無法通過力扣的判題系統,會超時。

由于split是單調函數,且符合二分查找技巧進行優化的標志,所以可以試圖改造成二分查找。

那么應該使用搜索左側邊界的二分查找,還是搜索右側邊界的二分查找呢?這個還是要看我們的算法邏輯:

intlo=getMax(nums),hi=getSum(nums); for(intmax=lo;max<=?hi;?max++)?{ ????int?n?=?split(nums,?max); ????if?(n?<=?m)?{ ????????return?max; ????} }

可能存在多個max使得split(nums, max)算出相同的n,因為我們的算法會返回最小的那個max,所以應該使用搜索左側邊界的二分查找算法。

現在,問題變為:在閉區間[lo, hi]中搜索一個最小的max,使得split(nums, max)恰好等于m。

那么,我們就可以直接套用搜索左側邊界的二分搜索框架改寫代碼:

intsplitArray(int[]nums,intm){ //一般搜索區間是左開右閉的,所以hi要額外加一 intlo=getMax(nums),hi=getSum(nums)+1; while(lom){ //最大子數組和上限低了,增加一些 lo=mid+1; } } returnlo; } intsplit(int[]nums,intmax){/*見上文*/} intgetMax(int[]nums){/*見上文*/} intgetSum(int[]nums){/*見上文*/}

這段二分搜索的代碼就是標準的搜索左側邊界的代碼框架,如果不理解可以參見前文二分查找框架詳解,這里就不展開了。

至此,這道題就通過二分查找技巧高效解決了。假設nums元素個數為N,元素和為S,則split函數的復雜度為O(N),二分查找的復雜度為O(logS),所以算法的總時間復雜度為O(N*logS)

責任編輯:lq

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 算法
    +關注

    關注

    23

    文章

    4625

    瀏覽量

    93138
  • 函數
    +關注

    關注

    3

    文章

    4344

    瀏覽量

    62832
  • 數組
    +關注

    關注

    1

    文章

    417

    瀏覽量

    25994

原文標題:二分查找算法如何運用?我和快手面試官進行了深入探討…

文章出處:【微信號:TheAlgorithm,微信公眾號:算法與數據結構】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    DAC3482設置DACCLK時,到底需要設置成和DATACLK相等還是二分之一的關系?

    =DACCLK時則可以看到報警寄存器先為不沖突,一段時間后變為1-away,再過一段時間變為2-away,再過一段時間變為fifo-collision,依次循環,請問我設置DACCLK時到底需要設置成和DATACLK相等還是二分之一的關系????求解救啊
    發表于 01-08 07:24

    通過安卓手機查找IP地址步驟

    —找到設置—點擊雙卡與移動網絡 ②點擊雙卡與移動網絡中的高級設置 ③查看IP地址 在最下方就可以看到IP地址 方法 打開手機瀏覽器—輸入my ip address—即可查到IP地址相關信息 、如何在手機上查找公網IP地址 相
    的頭像 發表于 12-12 13:53 ?337次閱讀
    通過安卓手機<b class='flag-5'>查找</b>IP地址步驟

    為什么DAC7811輸出電壓是理論值的二分之一?

    為什么輸出電壓是理論值的二分之一?
    發表于 12-12 07:58

    Linux文件查找

    Linux文件查找 1.find查找概述 為什么要有文件查找,因為很多時候我們可能會忘了某個文件所在的位置,此時就需要通過find來查找。 find命令可以根據不同的條件來進行
    的頭像 發表于 12-03 17:09 ?310次閱讀

    【「從算法到電路—數字芯片算法的電路實現」閱讀體驗】+一本介紹基礎硬件算法模塊實現的好書

    的。 第一章簡介了芯片研發流程,算法和電路設計,算法和芯片驗證的關系,算法工具等第章介紹了基本的數字電路基礎,具備基本的計算機或者數字電路教育的這部分知識應該已經了解了。不過一些內容
    發表于 11-20 13:42

    AFE5818的幀時鐘FCLK不等于clkin,是它的二分頻,請問是為什么?

    AFE5818的幀時鐘FCLK不等于clkin,是它的二分頻,請問是為什么?
    發表于 11-18 08:34

    華納云:Chord算法如何管理節點間的聯系?

    finger表中查找最近的節點來實現。如果當前節點的finger表中沒有直接指向目標節點的條目,它會將請求轉發給finger表中指向的節點,直到找到目標節點。 動態操作和故障處理: Chord算法需要
    發表于 11-08 16:03

    直流接地故障的查找程序和方法

    流饋線;先拉儲能、信號(公共屏)、測控,后拉保護、主變等裝置;拉開保護裝置電源后再上電前,需退相關保護裝置出口壓板。 、查找步驟 判斷接地性質 : 在直流系統出現接地的情況下,要先按照變電所絕緣監測裝置的具體配置,通過
    的頭像 發表于 10-08 10:26 ?662次閱讀

    如何高效查找電氣故障

    在現代工業生產中,電氣系統的穩定運行對于確保生產安全和效率至關重要。然而,電氣故障的發生往往不可避免,因此快速準確地查找并解決這些故障成為了電工和技術人員必備的技能。以下是一些高效查找電氣故障的方法
    的頭像 發表于 09-30 15:20 ?319次閱讀

    怎樣使用模擬電路實現信號的二分頻呢?

    請問怎樣使用模擬電路實現信號的二分頻呢?
    發表于 09-10 08:06

    如何查找線路漏電的方法和步驟

    線路漏電是電氣設備和線路中常見的故障之一,它不僅會導致設備損壞,還可能引發火災等安全事故。因此,查找和處理線路漏電問題至關重要。 確定漏電類型 首先,我們需要確定漏電的類型。漏電分為兩種:一種是接地
    的頭像 發表于 08-26 09:07 ?2221次閱讀

    明治案例 | 【AI二分類】剝蒜機大蒜方向識別

    ,就有了大蒜脫皮機,一鐘輕輕松松剝1斤~而在這個設備上,必然也少不了明治傳感其中的應用,本期小明就來分享一下~應用場景在自動剝蒜機中,需要設備精準判斷蒜瓣的方向,
    的頭像 發表于 07-16 08:25 ?238次閱讀
    明治案例 | 【AI<b class='flag-5'>二分</b>類】剝蒜機大蒜方向識別

    次回路多點接地故障查找儀裝置構成及原理——每日了解電力知識

    今天武漢摩恩智能電氣有限公司帶大家了解一下MEZN-6000 次回路多點接地故障查找儀。 MEZN-6000 次回路多點接地故障查找儀裝置的構成: 本裝置由分析儀、探測儀和信號采集
    的頭像 發表于 06-11 10:12 ?427次閱讀
    <b class='flag-5'>二</b>次回路多點接地故障<b class='flag-5'>查找</b>儀裝置構成及原理——每日了解電力知識

    如何用C語言實現高效查找二分法)

    今天給分享一下使用C語言實現二分算法,主要包含以下幾部分內容:二分查找算法介紹二分
    的頭像 發表于 06-04 08:04 ?1223次閱讀
    如何用C語言實現高效<b class='flag-5'>查找</b>(<b class='flag-5'>二分</b>法)

    二分頻電路總述 二分頻電路的功能實現

    分頻就是用同一個時鐘信號通過一定的電路結構轉變成不同頻率的時鐘信號。
    的頭像 發表于 03-06 17:13 ?2565次閱讀
    <b class='flag-5'>二分</b>頻電路總述 <b class='flag-5'>二分</b>頻電路的功能實現
    主站蜘蛛池模板: 一级a性色生活片毛片| 人人看人人添人人爽| 呦交小u女国产秘密入口| 国产精品一级毛片不收费| 欧美三级在线观看视频| 五月天婷婷色图| 视频三区| 亚洲一区高清| 日本免费不卡一区| 一级黄色免费毛片| 色日本视频| 四虎在线精品免费高清在线| 在线天堂网www资源种子| 免看一级a毛片一片成人不卡| 六月丁香激情网| 日本69sex护士| 亚洲成年网站| 欧美三级图片| 日本口工禁漫画无遮挡全彩| 激情九月婷婷| 中文天堂最新版在线中文| 日本一二区视频| 亚洲欧美婷婷| 日韩毛片网| 女人张开腿给人桶免费视频| 狠狠色网站| 天天色天天综合网| 性精品| 4455四色永久免费| 在线天堂资源| 欧美色香蕉| 夜夜操网站| 天天插天天色| a看片| 99久久国产综合精品国| 亚洲人成影网站~色| 人人人人澡| 永久免费精品影视网站| 亚洲成a人伦理| 午夜精品在线免费观看| 狠狠色狠狠色综合日日小蛇|