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

算法通過村第十八關(guān)-回溯|青銅筆記|什么叫回溯(中篇)

這篇具有很好參考價(jià)值的文章主要介紹了算法通過村第十八關(guān)-回溯|青銅筆記|什么叫回溯(中篇)。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。


前言


提示:陽光好的時(shí)候,會感覺還可以活很久,甚至可以活出喜悅。 --余秀華

回溯是非常重要的算法思想之一,主要解決一些暴力枚舉也搞不定的問題(這里埋個(gè)坑??)例如組合、分割、子集、棋盤等等。從性能角度來看回溯算法的效率并不是很高,但是對于暴力也解決不了的問題,它往往很快可以出結(jié)果,效率低就可以理解了吧。接下來,就看看回溯的事情吧??

回溯的核心問題

遞歸+局部枚舉+放下前任

接著看這個(gè)題目:77. 組合 - 力扣(LeetCode)

算法通過村第十八關(guān)-回溯|青銅筆記|什么叫回溯(中篇),算法集訓(xùn)營,算法筆記,什么叫回溯,保留狀態(tài),撤銷操作,Java
當(dāng)n = 4時(shí),我們可以選擇的有n有{1,2,3,4}這四種情況,所以我們從第一層到第二層的分支有四個(gè),分別表示可取1,2,3,4.而且這里從左到右取數(shù),取過的數(shù),不在重復(fù)取。第一次取1,集合變?yōu)?,3,4.因?yàn)閗= 2,我們也只能再取1個(gè)數(shù)就可以了,分別取2,3,4.得到的集合就是[1,2]、[1,3]、[1,4]。一次類推:

橫向:

算法通過村第十八關(guān)-回溯|青銅筆記|什么叫回溯(中篇),算法集訓(xùn)營,算法筆記,什么叫回溯,保留狀態(tài),撤銷操作,Java
每次從集合中選取元素,可選擇的范圍回逐步收縮,到了取4時(shí)就直接返為空了。

繼續(xù)觀察樹結(jié)構(gòu),可以發(fā)現(xiàn),圖中每次訪問到一個(gè)葉子節(jié)點(diǎn)(圖中的標(biāo)記處),我們就可以得到一個(gè)結(jié)果。雖然到最后時(shí)空的,但是不影響最終結(jié)果。這里相當(dāng)于從根節(jié)點(diǎn)開始每次選擇的內(nèi)容(分支)達(dá)到葉子節(jié)點(diǎn)時(shí),將其收起起來就是我們想要的結(jié)果。

你可以嘗試畫下n=5,k=3的結(jié)果:有沒有感覺

算法通過村第十八關(guān)-回溯|青銅筆記|什么叫回溯(中篇),算法集訓(xùn)營,算法筆記,什么叫回溯,保留狀態(tài),撤銷操作,Java
從圖中我們發(fā)現(xiàn)元素個(gè)數(shù)n相當(dāng)于樹的寬度(橫向),而每個(gè)結(jié)果的元素個(gè)數(shù)k相當(dāng)于樹的深度(縱向)。所以我們說回溯問題就是一縱一橫而已。在分析我們回發(fā)現(xiàn)下面幾個(gè)規(guī)律:

  • 我們每次選擇都是從類似{1,2,3,4},{1,2,3,4}這個(gè)樣的序列中一個(gè)一個(gè)選的,這就是為什么說是局部枚舉,后面的枚舉范圍回越來越小。
  • 枚舉時(shí),我們就是簡單的暴露測試而已,一個(gè)一個(gè)驗(yàn)證,能否滿足要求,從上圖可以看到,這就是N叉樹的遍歷過程,一次代碼相似度很高。
  • 我們再看葉子過程,這部分是不是和(n = 4,k = 2)處理的結(jié)果一致,也就說是很明顯的遞歸結(jié)構(gòu)。

到此,我們還有一個(gè)問題待解決,就是回溯一般會有一個(gè)手動(dòng)撤銷的操作,為什么要這么做呢?

繼續(xù)觀察縱橫圖:
算法通過村第十八關(guān)-回溯|青銅筆記|什么叫回溯(中篇),算法集訓(xùn)營,算法筆記,什么叫回溯,保留狀態(tài),撤銷操作,Java
我們可以看到,我們收集的每個(gè)結(jié)果不是針對葉子節(jié)點(diǎn)的,而是針對樹枝的,比如最上層我們首先確定了1,下層我們?nèi)绻x擇了2,那么結(jié)果就是{1,2},如果選擇了3,結(jié)果就是{1,3}.一次類推。現(xiàn)在時(shí)怎么確定得到第一個(gè)結(jié)果時(shí){1,2}之后,得到第二個(gè)結(jié)果是{1,3}呢?

繼續(xù)觀察縱橫圖 ,可以看到,我們在得到{1,2}之后將2撤銷,再繼續(xù)使用3,就得到了{(lán)1,3},同理也可以得到{1,4},之后這一層就沒有了,我們可以撤銷1,繼續(xù)從最上層取2繼續(xù)進(jìn)行。

這里對應(yīng)的代碼操作就是先將第一個(gè)結(jié)果放在臨時(shí)列表的Path里面,得到第一個(gè)結(jié)果{1,2},之后就將path里面的內(nèi)容放進(jìn)結(jié)果列表resultList中,之后,將path里面的2撤銷掉,繼續(xù)尋找下一個(gè)結(jié)果{1,3},繼續(xù)將path加入resultList中,然后再次撤銷,繼續(xù)尋找。

現(xiàn)在了解為什么要撤銷,看圖。這個(gè)過程,我們稱它“放下前任,繼續(xù)前進(jìn)”,后面的回溯大都是這樣的思路。

這幾條就是回溯的基本規(guī)律,了解這一點(diǎn),我們就可以看看代碼是怎么回事了,到此我們看看完整的代碼時(shí)怎樣的:

 public List<List<Integer>> combine(int n, int k) {
        List<List<Integer>> res = new ArrayList<>();
        if (k <=0 || n < k){
            return res;
        }
?
        Deque<Integer> path = new ArrayDeque<>();
?
        dfs(n,k,1,path,res);
        return res;
    }
?
    public void dfs(int n,int k,int startIndex,Deque<Integer> path,List<List<Integer>> res){
        // 遞歸終止條件,path 等于k(剛好完成一次
        if (path.size() == k){
            res.add((new ArrayList<>(path)));
            return;
        }
        // 針對每個(gè)節(jié)點(diǎn),這里就是遍歷搜索,也就是枚舉
        for(int i = startIndex; i <= n; i++){
            // 向路徑里添加一個(gè)數(shù)(分支里的取值
            path.addLast(i);
            // 搜索起點(diǎn)要加1,就是縮小范圍,準(zhǔn)備下一輪遞歸(這里不允許重復(fù)
            dfs(n,k,i + 1,path,res);
            // 遞歸之后要做同樣的逆向操作,撤銷掉
            path.removeLast();
        }
    }

上面代碼還有一個(gè)問題需要解釋:startIndex和i是怎么變化的,為什么要傳遞到下一層(+ 1)

我們來看看這里的遞歸循環(huán):

   // 針對每個(gè)節(jié)點(diǎn),這里就是遍歷搜索,也就是枚舉
        for(int i = startIndex; i <= n; i++){
            // 向路徑里添加一個(gè)數(shù)(分支里的取值
            path.addLast(i);
            // 搜索起點(diǎn)要加1,就是縮小范圍,準(zhǔn)備下一輪遞歸(這里不允許重復(fù)
            dfs(n,k,i + 1,path,res);
            // 遞歸之后要做同樣的逆向操作,撤銷掉
            path.removeLast();
        }

這里的循環(huán)有什么作用呢?看看這里,其實(shí)來說是一個(gè)枚舉,第一次n=4,可以選擇1,2,3,4四種情況,所以就存在4個(gè)分支,for就需要執(zhí)行4次:
算法通過村第十八關(guān)-回溯|青銅筆記|什么叫回溯(中篇),算法集訓(xùn)營,算法筆記,什么叫回溯,保留狀態(tài),撤銷操作,Java
對于第二層來說,第一個(gè)數(shù),選擇1之后,身下的元素就只有2,3,4了。所以這時(shí)候for循環(huán)就執(zhí)行3次,后面的只有2次和1次了。

撤銷操作解釋

如果你還是不清楚的話,這里就帶圖詳細(xì)的走一遍,回溯也就是這個(gè)地方有點(diǎn)暈,拿下就是勝利?。

   // 針對每個(gè)節(jié)點(diǎn),這里就是遍歷搜索,也就是枚舉
        for(int i = startIndex; i <= n; i++){
            // 向路徑里添加一個(gè)數(shù)(分支里的取值
            path.addLast(i);
            // 搜索起點(diǎn)要加1,就是縮小范圍,準(zhǔn)備下一輪遞歸(這里不允許重復(fù)
            dfs(n,k,i + 1,path,res);
            // 遞歸之后要做同樣的逆向操作,撤銷掉
            path.removeLast();
        }

為什么要remove呢?看下圖,當(dāng)?shù)谝粚尤?時(shí),最底層的遍歷從左到右執(zhí)行,取2,取3,取4.而取3的時(shí)候,此時(shí)res里面存儲的是{1,2},所以這里前提是需要撤銷掉2(path.removeLast();)的作用。

這里我們拆解一下遞歸方法,將遞歸拆分成函數(shù)調(diào)用,輸出第一條路徑{1,2}的步驟如下:
算法通過村第十八關(guān)-回溯|青銅筆記|什么叫回溯(中篇),算法集訓(xùn)營,算法筆記,什么叫回溯,保留狀態(tài),撤銷操作,Java
我們在遞歸說過一個(gè)特點(diǎn):不到南墻不回頭,回溯也是這個(gè)道理,我們看看這個(gè)過程。

算法通過村第十八關(guān)-回溯|青銅筆記|什么叫回溯(中篇),算法集訓(xùn)營,算法筆記,什么叫回溯,保留狀態(tài),撤銷操作,Java
然后,怎么在次進(jìn)行呢,這里就需要撤回一下了,但是如果將這里的remove代碼去掉,就會是這個(gè)樣子:
算法通過村第十八關(guān)-回溯|青銅筆記|什么叫回溯(中篇),算法集訓(xùn)營,算法筆記,什么叫回溯,保留狀態(tài),撤銷操作,Java
這里知道遍歷完成,然會的就不做撤銷,就會下一場進(jìn)入for循環(huán),也就是回變成{1,2,3}.

path是一個(gè)全局的引用的,各個(gè)遞歸的函數(shù)是公用的,所以這里處理完{1,2},之后,需要把2撤出去,將1保留,再讓三進(jìn)入,從而得到{1,3}.所以這里不許remove一下的。

同樣處理完之后,后續(xù)的也是依次處理,需要撤銷的,這里也就是不得不處理撤銷的操作。


總結(jié)

提示:什么叫回溯;保留狀態(tài);撤銷操作;回溯核心思想;回溯的入門


如果有幫助到你,請給題解點(diǎn)個(gè)贊和收藏,讓更多的人看到 ~ ("▔□▔)/

如有不理解的地方,歡迎你在評論區(qū)給我留言,我都會逐一回復(fù) ~

也歡迎你 關(guān)注我 ,喜歡交朋友,喜歡一起探討問題。

算法通過村第十八關(guān)-回溯|青銅筆記|什么叫回溯(中篇),算法集訓(xùn)營,算法筆記,什么叫回溯,保留狀態(tài),撤銷操作,Java文章來源地址http://www.zghlxwxcb.cn/news/detail-741507.html

到了這里,關(guān)于算法通過村第十八關(guān)-回溯|青銅筆記|什么叫回溯(中篇)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

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

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

相關(guān)文章

  • 算法通過村第四關(guān)-棧黃金筆記|表達(dá)式問題

    算法通過村第四關(guān)-棧黃金筆記|表達(dá)式問題

    提示:快樂的人沒有過去,不快樂的人除了過去一無所有。 --理查德·弗蘭納根《深入北方的小路》 棧的進(jìn)階來了,還記得棧的使用場景嗎?表達(dá)式和符號,這不就來了 參考題目介紹:227. 基本計(jì)算器 II - 力扣(LeetCode) 計(jì)算問題在棧的運(yùn)用也是非常廣泛的。在乘除優(yōu)先于加

    2024年02月10日
    瀏覽(14)
  • 算法通過村第二關(guān)-鏈表黃金筆記|K個(gè)一組反轉(zhuǎn)

    算法通過村第二關(guān)-鏈表黃金筆記|K個(gè)一組反轉(zhuǎn)

    提示:沒有人天生就喜歡一種氣味而討厭另一種氣味。文明的暗示而已。 給你鏈表的頭節(jié)點(diǎn) head ,每 k 個(gè)節(jié)點(diǎn)一組進(jìn)行翻轉(zhuǎn),請你返回修改后的鏈表。 k 是一個(gè)正整數(shù),它的值小于或等于鏈表的長度。如果節(jié)點(diǎn)總數(shù)不是 k 的整數(shù)倍,那么請將最后剩余的節(jié)點(diǎn)保持原有順序。

    2024年02月14日
    瀏覽(18)
  • 算法通過村第五關(guān)-隊(duì)列和Hash黃金筆記|LRU的設(shè)計(jì)與實(shí)現(xiàn)

    算法通過村第五關(guān)-隊(duì)列和Hash黃金筆記|LRU的設(shè)計(jì)與實(shí)現(xiàn)

    提示:我曾如此渴望命運(yùn)的波瀾,到最后才發(fā)現(xiàn):人生最曼妙的風(fēng)景,竟是內(nèi)心的淡定從容。 我們層如此盼望世界的認(rèn)可,到最后才知道:世界是自己,與他人毫無關(guān)系。 --楊絳 LRU 是非常經(jīng)典的問題,而且在常年的算法中也是熱門,但是他是存在技巧的,我們這就來一起看

    2024年02月09日
    瀏覽(21)
  • 算法通關(guān)村第十八關(guān)——排列問題

    LeetCode46.給定一個(gè)沒有重復(fù)數(shù)字的序列,返回其所有可能的全排列。例如: 輸入:[1,2,3] 輸出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] 元素1在[1,2]中已經(jīng)使用過了,但是在[2,1]中還要再使用一次,所以就不能使用startlndex了,為此可以使用一個(gè)used數(shù)組來標(biāo)記已經(jīng)選擇的元

    2024年02月09日
    瀏覽(22)
  • 算法通關(guān)第十九關(guān)-青銅挑戰(zhàn)理解動(dòng)態(tài)規(guī)劃

    算法通關(guān)第十九關(guān)-青銅挑戰(zhàn)理解動(dòng)態(tài)規(guī)劃

    大家好我是蘇麟 , 今天聊聊動(dòng)態(tài)規(guī)劃 . 動(dòng)態(tài)規(guī)劃是最熱門、最重要的算法思想之一,在面試中大量出現(xiàn),而且題目整體都偏難一些對于大部人來說,最大的問題是不知道動(dòng)態(tài)規(guī)劃到底是怎么回事。很多人看教程等,都被里面的狀態(tài)子問題、狀態(tài)轉(zhuǎn)移方程等等勸退了。 其實(shí),所

    2024年02月03日
    瀏覽(31)
  • 算法通關(guān)村第十七關(guān):青銅挑戰(zhàn)-貪心其實(shí)很簡單

    算法通關(guān)村第十七關(guān):青銅挑戰(zhàn)-貪心其實(shí)很簡單

    1. 難以解釋的貪心算法 貪心學(xué)習(xí)法則:直接做題,不考慮貪不貪心 貪心(貪婪)算法 是指在問題盡心求解時(shí),在每一步選擇中都采取最好或者最優(yōu)(最有利)的選擇,從而希望能夠?qū)е陆Y(jié)果最好或者最優(yōu)的算法 貪心算法所得到的結(jié)果不一定是最優(yōu)的結(jié)果,但是都是相對近似最

    2024年02月09日
    瀏覽(28)
  • 算法通關(guān)村第十六關(guān):青銅挑戰(zhàn)-滑動(dòng)窗口其實(shí)很簡單

    算法通關(guān)村第十六關(guān):青銅挑戰(zhàn)-滑動(dòng)窗口其實(shí)很簡單

    1. 滑動(dòng)窗口基本思想 數(shù)組引入雙指針的背景: 很多算法會大量移動(dòng)數(shù)組中的元素,頻繁移動(dòng)元素會導(dǎo)致執(zhí)行效率低下或者超時(shí),使用兩個(gè)變量能比較好的解決很多相關(guān)問題 數(shù)組雙指針,之前介紹過 對撞型 和 快慢型 兩種,滑動(dòng)窗口思想就是快慢型的特例 滑動(dòng)窗口 示例:

    2024年02月09日
    瀏覽(26)
  • 算法通關(guān)村第十五關(guān):青銅-用4KB內(nèi)存尋找重復(fù)元素

    位運(yùn)算在查找元素中的妙用 題目要求: 給定一個(gè)數(shù)組,包含從1到N的整數(shù),N最大為32000,數(shù)組可能還有重復(fù)值,且N的取值不定,若只有4KB的內(nèi)存可用,該如何打印數(shù)組中所有重復(fù)元素。 思路分析 本題是非常典型的海量數(shù)據(jù)處理的問題,使用的是位運(yùn)算結(jié)構(gòu) 內(nèi)存大小關(guān)系

    2024年02月10日
    瀏覽(18)
  • [Go版]算法通關(guān)村第十五關(guān)青銅——用4KB內(nèi)存尋找重復(fù)元素

    在 海量數(shù)據(jù) 中,此時(shí)普通的數(shù)組、鏈表、Hash、樹等等結(jié)構(gòu)有無效了 ,因?yàn)閮?nèi)存空間放不下了。而常規(guī)的遞歸、排序,回溯、貪心和動(dòng)態(tài)規(guī)劃等思想也無效了,因?yàn)閳?zhí)行都會超時(shí),必須另外想辦法。這類問題該如何下手呢?這里介紹三種非常典型的思路: 使用位存儲 ,使用

    2024年02月11日
    瀏覽(36)
  • [Go版]算法通關(guān)村第一關(guān)青銅——鏈表青銅挑戰(zhàn)筆記

    [Go版]算法通關(guān)村第一關(guān)青銅——鏈表青銅挑戰(zhàn)筆記

    單向鏈表圖示: 雙向鏈表圖示: 環(huán)形單向鏈表圖示: 環(huán)形雙向鏈表圖示: 源碼地址: GitHub-golang版本 如果是單向的,需要將當(dāng)前節(jié)點(diǎn) 定位到要插入節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn) ,否則一旦過了將無法回頭找到前一個(gè)節(jié)點(diǎn) 如果是雙向的,將當(dāng)前節(jié)點(diǎn) 定位到要插入節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)、

    2024年02月13日
    瀏覽(21)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包