<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          宏觀視角看遞歸

          共 3718字,需瀏覽 8分鐘

           ·

          2021-03-17 23:57

          Hi,你好,今天的文章主要是從宏觀角度聊聊遞歸這種算法思想,文章主要內(nèi)容如下:
          • 通過(guò)數(shù)組求和看遞歸的基本性質(zhì)

          • 鏈表的天然遞歸性

          01

          通過(guò)數(shù)組求和看遞歸的基本性質(zhì)

          現(xiàn)在給出一個(gè)數(shù)組arr={1,3,6},問(wèn)如何用遞歸方式求出數(shù)組中所有元素的總和。
          遞歸思想介紹
          假設(shè)現(xiàn)在A拿到了這個(gè)問(wèn)題,但是A只能計(jì)算數(shù)組中的第一個(gè)元素值和剩余元素總和的和,那這時(shí)怎么辦呢?
          A就想,我可以先把數(shù)組中第一個(gè)元素1的值記錄下來(lái),然后讓B計(jì)算數(shù)組中剩余元素的總和。
          于是,B就收到一個(gè)任務(wù),需要計(jì)算數(shù)組{3,6}的總和,同樣的B和A一樣也只能計(jì)算數(shù)組中的第一個(gè)元素值和剩余元素總和的和。因此,B記錄下他拿到的數(shù)組中的第一個(gè)元素3的值,然后讓C去計(jì)算數(shù)組中剩余元素的總和。
          這時(shí),C收到一個(gè)任務(wù),是計(jì)算數(shù)組{6}的總和,同樣的C和A一樣也只能計(jì)算數(shù)組中的第一個(gè)元素值和剩余元素總和的和,并且除了第一個(gè)元素外,C不知道數(shù)組中還剩余哪些元素。于是,C將數(shù)組中的第一個(gè)元素6的值記錄下來(lái),然后讓D去計(jì)算數(shù)組中剩余元素的總和。
          D在收到任務(wù)后,一看數(shù)組是空的,就知道數(shù)組中元素總和是0。
          然后D就告訴C,剩余元素的總和是0。于是C將自己記錄的元素6和D告訴他的剩余元素的總和0相加后得到6,他就把這個(gè)結(jié)果告訴了B。
          B在收到C的結(jié)果6后,同樣的將自己記錄的元素3和其相加得到9,于是他就把這個(gè)結(jié)果告訴了A。
          A在拿到B告訴他的結(jié)果9后,將其和自己記錄的元素1相加得到結(jié)果10。這時(shí)A就知道數(shù)組中所有元素的總和是10。
          上述過(guò)程中A拿到求數(shù)組中所有元素和這個(gè)問(wèn)題后,將其告訴B,B再告訴C,C再告訴D,這個(gè)過(guò)程我們可以稱之為”遞“
          然后,D將結(jié)果告訴C,C再告訴B,B在告訴A的這個(gè)過(guò)程我們可以稱之為”歸“。
          遞歸要滿足的條件
          在上述問(wèn)題的描述中,其實(shí)就包含了遞歸這種算法思想的一些基本條件:
          一是一個(gè)問(wèn)題可以分解為多個(gè)更小的子問(wèn)題并且這多個(gè)更小的子問(wèn)題的求解思路完全一樣
          對(duì)于數(shù)組求和這個(gè)問(wèn)題來(lái)說(shuō),A要知道自己拿到的數(shù)組的總和這個(gè)問(wèn)題,可以分解為B要知道除去數(shù)組第一個(gè)元素外剩余元素總和這樣一個(gè)問(wèn)題。
          同時(shí),對(duì)于A和B來(lái)說(shuō),他們求解問(wèn)題的思路是一樣的,即只計(jì)算自己拿到的數(shù)組中第一個(gè)元素值和數(shù)組中剩余元素總和的和,而不管數(shù)組中剩余元素總和的和是如何計(jì)算的。
          二是存在一個(gè)終止條件,可以讓遞歸停下來(lái)。
          比如數(shù)組求和的終止條件就是數(shù)組中沒(méi)有剩余元素需要計(jì)算了。
          數(shù)組求和的遞歸思路具體如下圖:
          遞歸代碼的編寫(xiě)
          遞歸代碼的編寫(xiě)一是要知道遞歸終止條件,對(duì)于數(shù)組求和這個(gè)問(wèn)題來(lái)說(shuō),其終止條件是數(shù)組中沒(méi)有元素需要計(jì)算了,代碼表示是:
          // begin 表示從數(shù)組中哪個(gè)索引位置開(kāi)始// 當(dāng)begin == arr.length表示數(shù)組中沒(méi)有剩余元素if (begin == arr.length) {    return 0;}

          二是要知道遞歸遞推公式,就數(shù)組求和這個(gè)問(wèn)題來(lái)說(shuō),遞推公式是:

          arr[begin] + sum(begin + 1, arr);

          有了終止條件和遞推公式,就可以寫(xiě)出遞歸求解數(shù)組中所有元素和的代碼了,實(shí)現(xiàn)如下:

          public int sum (int[] arr) {    // 調(diào)用遞歸函數(shù),初始從0開(kāi)始    return sum(0, arr);}
          // 遞歸函數(shù)private int sum(int begin, int[] arr) { // begin 表示從數(shù)組中哪個(gè)索引位置開(kāi)始 // 當(dāng)begin == arr.length表示數(shù)組中沒(méi)有剩余元素 if (begin == arr.length) { return 0; }
          // 我只計(jì)算我拿到的數(shù)組中第一個(gè)元素的值 // 和數(shù)組中剩余元素總和的和    return arr[begin] + sum(begin + 1, arr); // 遞歸調(diào)用}

          這里我們?cè)诘?行sum(int begin, int[] arr)這個(gè)方法中調(diào)用了sum(int begin, int[] arr)方法它自己,即16行的sum(begin + 1, arr),這一點(diǎn)可能會(huì)讓你覺(jué)得困惑。

          我們可以這樣理解,方法sum(int begin, int[] arr)是計(jì)算數(shù)組中從索引begin開(kāi)始所有元素的總和,而該方法的計(jì)算規(guī)則是我計(jì)算的是當(dāng)前數(shù)組起始位置begin所對(duì)應(yīng)的元素值和數(shù)組中剩余元素的總和的和。那么,我就需要有個(gè)方法可以告訴我數(shù)組中剩余元素的總和是多少。

          這時(shí),剛好有個(gè)方法fun(int begin, int[] arr),只要我告訴它數(shù)組是什么樣的,以及從哪個(gè)索引位置開(kāi)始計(jì)算,它就會(huì)告訴我數(shù)組中剩余元素的總和。只不過(guò)這個(gè)方法fun(int begin, int[] arr)所需的參數(shù)和我自己一樣而已。于是,在代碼中看起來(lái)就是方法sum(int begin, int[] arr)調(diào)用了它自己。


          02

          鏈表的天然遞歸性

          接著我們看下如何用遞歸思想解答LeetCode中#203.移除鏈表元素這個(gè)問(wèn)題。

          題目描述

          刪除鏈表中等于給定值 val 的所有節(jié)點(diǎn)。 


          示例

          輸入: 1->2->6->3->4->5->6, val = 6 

          輸出: 1->2->3->4->5

          LeetCode
          思路分析
          為了方便演示,我將題目示例中給定的鏈表進(jìn)行了簡(jiǎn)化。如下圖:
          先看下”遞“的過(guò)程,對(duì)于A來(lái)說(shuō),他在拿到給定的鏈表后,記錄下了頭節(jié)點(diǎn),然后將頭結(jié)點(diǎn)之后的鏈表給了B。
          同樣的B在拿到給定的鏈表后,記錄下了頭節(jié)點(diǎn),然后將頭結(jié)點(diǎn)之后的鏈表給了C。
          C在拿到給定的鏈表后,記錄下了頭節(jié)點(diǎn),然后將頭結(jié)點(diǎn)之后的鏈表給了D。
          D在拿到給定的鏈表后,記錄下了頭節(jié)點(diǎn),然后將頭結(jié)點(diǎn)之后的鏈表給了E。
          這時(shí)E拿到的鏈表是一個(gè)空鏈表。
          E拿到空鏈表之后,就將其返回給了D,這時(shí)D就知道它的鏈表是3—>null。
          D將自己得到的結(jié)果3>null返回給了C,這時(shí)C就知道的鏈表是6>3>null。
          接著C需要將自己計(jì)算的結(jié)果返回給B,但這時(shí)C發(fā)現(xiàn)自己拿的鏈表的頭結(jié)點(diǎn)是和要移除的元素val=6相等的,因此C返回B的結(jié)果應(yīng)該是去掉頭結(jié)點(diǎn)6后的剩余部分3>null。
          B在拿到C返回的結(jié)果后,就知道它的鏈表是2>3>null。然后,它將這個(gè)結(jié)果告訴了A。
          A在拿到B返回的結(jié)果后,就知道它的鏈表是1>2>3>null,也就是移除鏈表中元素val=6之后的結(jié)果。
          對(duì)于上述的遞歸過(guò)程,可以簡(jiǎn)化為兩個(gè)步驟:
          一是記錄下鏈表當(dāng)前頭結(jié)點(diǎn)head,然后調(diào)用移除鏈表中結(jié)點(diǎn)值val=6的方法;
          二是在拿到調(diào)用方法之后的結(jié)果時(shí),判斷一下當(dāng)前記錄的頭結(jié)點(diǎn)的值是不是等于val=6,如果不等,則將調(diào)用方法之后的結(jié)果掛在所記錄的頭結(jié)點(diǎn)之后,返回;如果相等,則直接將調(diào)用方法之后的結(jié)果返回。

          鏈表這種數(shù)據(jù)結(jié)構(gòu),我們說(shuō)它具有天然遞歸性,就在于對(duì)于一個(gè)鏈表,我們可以將其分解為頭結(jié)點(diǎn)和一個(gè)子鏈表。然后,對(duì)于子鏈表同樣可以分解為一個(gè)頭結(jié)點(diǎn)和一個(gè)子鏈表。這滿足的是遞歸思想中的:一個(gè)問(wèn)題可以分解為多個(gè)子問(wèn)題并且這多個(gè)子問(wèn)題求解思路是一樣的這一條件。
          此外,對(duì)于鏈表分解到最后時(shí),頭結(jié)點(diǎn)為null,這滿足的是遞歸思想中的:存在遞歸終止條件,讓遞歸停下來(lái)這一條件。
          代碼實(shí)現(xiàn)
          public ListNode removeElements(ListNode head, int val) {    // 遞歸終止條件    if (head == null) {        return null;    }
          // 調(diào)用方法removeElements將當(dāng)前結(jié)點(diǎn)之后的鏈表部分中的 // 和val值相等的結(jié)點(diǎn)刪除 ListNode result = removeElements(head.next, val);
          // 如果當(dāng)前結(jié)點(diǎn)head的值等于val則返回result if (head.val == val) { return result; } else { // 如果當(dāng)前結(jié)點(diǎn)head的值不等于val則 // 將result掛在當(dāng)前結(jié)點(diǎn)head之后返回 head.next = result; return head; }}

          題圖:stux / Pixabay

          瀏覽 23
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产成人高清视频在线观看 | 91人妻人人澡人人爽人人精品 | 亚洲无码视频在线看 | 天天爱,天天操 | 日韩网站污 |