日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[递归]递归问题解题思路

發布時間:2023/12/15 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [递归]递归问题解题思路 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

遞歸解題三部曲

何為遞歸?程序反復調用自身即是遞歸。

我自己在剛開始解決遞歸問題的時候,總是會去糾結這一層函數做了什么,它調用自身后的下一層函數又做了什么…然后就會覺得實現一個遞歸解法十分復雜,根本就無從下手。

相信很多初學者和我一樣,這是一個思維誤區,一定要走出來。既然遞歸是一個反復調用自身的過程,這就說明它每一級的功能都是一樣的,因此我們只需要關注一級遞歸的解決過程即可。

如上圖所示,我們需要關心的主要是以下三點:

  • 整個遞歸的終止條件。
  • 一級遞歸需要做什么?
  • 應該返回給上一級的返回值是什么?
  • 因此,也就有了我們解遞歸題的三部曲:

  • 找整個遞歸的終止條件:遞歸應該在什么時候結束?
  • 找返回值:應該給上一級返回什么信息?
  • 本級遞歸應該做什么:在這一級遞歸中,應該完成什么任務?
  • 一定要理解這3步,這就是以后遞歸秒殺算法題的依據和思路。

    遞歸的三大要素

    第一要素:明確你這個函數想要干什么

    對于遞歸,我覺得很重要的一個事就是,這個函數的功能是什么,他要完成什么樣的一件事,而這個,是完全由你自己來定義的。也就是說,我們先不管函數里面的代碼什么,而是要先明白,你這個函數是要用來干什么。

    第二要素:尋找遞歸結束條件

    所謂遞歸,就是會在函數內部代碼中,調用這個函數本身,所以,我們必須要找出遞歸的結束條件,不然的話,會一直調用自己,進入無底洞。也就是說,我們需要找出當參數為啥時,遞歸結束,之后直接把結果返回,請注意,這個時候我們必須能根據這個參數的值,能夠直接知道函數的結果是什么。

    第三要素:找出函數的等價關系式

    第三要素就是,我們要不斷縮小參數的范圍,縮小之后,我們可以通過一些輔助的變量或者操作,使原函數的結果不變。

    ?

    例1:求二叉樹的最大深度

    先看一道簡單的Leetcode題目: Leetcode 104. 二叉樹的最大深度

    題目很簡單,求二叉樹的最大深度,那么直接套遞歸解題三部曲模版:

  • 找終止條件。 什么情況下遞歸結束?當然是樹為空的時候,此時樹的深度為0,遞歸就結束了。
  • 找返回值。 應該返回什么?題目求的是樹的最大深度,我們需要從每一級得到的信息自然是當前這一級對應的樹的最大深度,因此我們的返回值應該是當前樹的最大深度,這一步可以結合第三步來看。
  • 本級遞歸應該做什么。 首先,還是強調要走出之前的思維誤區,遞歸后我們眼里的樹一定是這個樣子的,看下圖。此時就三個節點:root、root.left、root.right,其中根據第二步,root.left和root.right分別記錄的是root的左右子樹的最大深度。那么本級遞歸應該做什么就很明確了,自然就是在root的左右子樹中選擇較大的一個,再加上1就是以root為根的子樹的最大深度了,然后再返回這個深度即可。
  • 具體代碼如下:

    # Definition for a binary tree node. # class TreeNode(object): # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution(object):def maxDepth(self, root):""":type root: TreeNode:rtype: int"""if root is None:return 0left_height = self.maxDepth(root.left)right_height = self.maxDepth(root.right)return max(left_height, right_height) + 1

    ?

    例2:兩兩交換鏈表中的節點

    看了一道遞歸套路解決二叉樹的問題后,有點套路搞定遞歸的感覺了嗎?我們再來看一道Leetcode中等難度的鏈表的問題,掌握套路后這種中等難度的問題真的就是秒:Leetcode 24. 兩兩交換鏈表中的節點

    直接上三部曲模版:

  • 找終止條件。 什么情況下遞歸終止?沒得交換的時候,遞歸就終止了唄。因此當鏈表只剩一個節點或者沒有節點的時候,自然遞歸就終止了。
  • 找返回值。 我們希望向上一級遞歸返回什么信息?由于我們的目的是兩兩交換鏈表中相鄰的節點,因此自然希望交換給上一級遞歸的是已經完成交換處理,即已經處理好的鏈表。
  • 本級遞歸應該做什么。 結合第二步,看下圖!由于只考慮本級遞歸,所以這個鏈表在我們眼里其實也就三個節點:head、head.next、已處理完的鏈表部分。而本級遞歸的任務也就是交換這3個節點中的前兩個節點,就很easy了。
  • 附上代碼:

    # Definition for singly-linked list. # class ListNode(object): # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution(object):def swapPairs(self, head):""":type head: ListNode:rtype: ListNode"""#終止條件:鏈表只剩一個節點或者沒節點了,沒得交換了。返回的是已經處理好的鏈表if head is None or head.next is None:return head#一共三個節點:head, next, swapPairs(next.next)#下面的任務便是交換這3個節點中的前兩個節點newHead = head.nexthead.next = self.swapPairs(newHead.next) newHead.next = head#根據第二步:返回給上一級的是當前已經完成交換后,即處理好了的鏈表部分return newHead

    ?

    例3:反轉單鏈表

    206. 反轉鏈表

    反轉單鏈表。例如鏈表為:1->2->3->4。反轉后為 4->3->2->1

    1. 定義遞歸函數功能

    假設函數 reverseList(head) 的功能是反轉但鏈表,其中 head 表示鏈表的頭節點

    2.尋找結束條件

    當鏈表只有一個節點,或者如果是空表的話,你應該知道結果吧?直接啥也不用干,直接把 head 返回

    3. 尋找等價關系

    它的等價條件中,一定是范圍不斷在縮小,對于鏈表來說,就是鏈表的節點個數不斷在變小,所以,如果你實在找不出,你就先對 reverseList(head.next) 遞歸走一遍,看看結果是咋樣的。

    先縮小范圍,先對 2->3->4遞歸下試試,即代碼如下

    class Solution:def reverseList(self, head: ListNode) -> ListNode:if not head or not head.next:return headnewHead = self.reverseList(head.next)

    們在第一步的時候,就已經定義了 reverseLis t函數的功能可以把一個單鏈表反轉,所以,我們對 2->3->4反轉之后的結果應該是這樣:

    我們把 2->3->4 遞歸成 4->3->2。不過,1 這個節點我們并沒有去碰它,所以 1 的 next 節點仍然是連接這 2。

    接下來呢?該怎么辦?

    其實,接下來就簡單了,我們接下來只需要把節點 2 的 next 指向 1,然后把 1 的 next 指向 null,不就行了?,即通過改變 newList 鏈表之后的結果如下:

    也就是說,reverseList(head) 等價于 reverseList(head.next) + 改變一下1,2兩個節點的指向。好了,等價關系找出來了,代碼如下(有詳細的解釋):

    class Solution:def reverseList(self, head: ListNode) -> ListNode:if not head or not head.next:return headnewHead = self.reverseList(head.next)#改變 1,2節點的指向。#通過 head.next獲取節點2t1 = head.next#讓 2 的 next 指向 2t1.next = head#1 的 next 指向 null.head.next = None#把調整之后的鏈表返回。return newHead

    ?

    例4:平衡二叉樹

    那么請你先不看以下部分,嘗試解決一下這道easy難度的Leetcode題(個人覺得此題比上面的medium難度要難):Leetcode 110. 平衡二叉樹

    我覺得這個題真的是集合了模版的精髓所在,下面套三部曲模版:

  • 找終止條件。 什么情況下遞歸應該終止?自然是子樹為空的時候,空樹自然是平衡二叉樹了。

  • 應該返回什么信息:

    為什么我說這個題是集合了模版精髓?正是因為此題的返回值。要知道我們搞這么多花里胡哨的,都是為了能寫出正確的遞歸函數,因此在解這個題的時候,我們就需要思考,我們到底希望返回什么值?

    何為平衡二叉樹?平衡二叉樹即左右兩棵子樹高度差不大于1的二叉樹。而對于一顆樹,它是一個平衡二叉樹需要滿足三個條件:它的左子樹是平衡二叉樹,它的右子樹是平衡二叉樹,它的左右子樹的高度差不大于1。換句話說:如果它的左子樹或右子樹不是平衡二叉樹,或者它的左右子樹高度差大于1,那么它就不是平衡二叉樹。

    而在我們眼里,這顆二叉樹就3個節點:root、left、right。那么我們應該返回什么呢?如果返回一個當前樹是否是平衡二叉樹的boolean類型的值,那么我只知道left和right這兩棵樹是否是平衡二叉樹,無法得出left和right的高度差是否不大于1,自然也就無法得出root這棵樹是否是平衡二叉樹了。而如果我返回的是一個平衡二叉樹的高度的int類型的值,那么我就只知道兩棵樹的高度,但無法知道這兩棵樹是不是平衡二叉樹,自然也就沒法判斷root這棵樹是不是平衡二叉樹了。

  • 本級遞歸應該做什么。 知道了第二步的返回值后,這一步就很簡單了。目前樹有三個節點:root,left,right。我們首先判斷left子樹和right子樹是否是平衡二叉樹,如果不是則直接返回false。再判斷兩樹高度差是否不大于1,如果大于1也直接返回false。否則說明以root為節點的子樹是平衡二叉樹,那么就返回true和它的高度。

  • ?

    判斷左右子樹的高度差是否超過1,依次遞歸

    # Definition for a binary tree node. # class TreeNode(object): # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution(object):def isBalanced(self, root):""":type root: TreeNode:rtype: bool"""if root is None:return Trueif abs(self.getHeight(root.left) - self.getHeight(root.right)) > 1:return Falsereturn self.isBalanced(root.left) and self.isBalanced(root.right)def getHeight(self, node):if node is None:return 0return max(self.getHeight(node.left), self.getHeight(node.right)) + 1

    ?

    ?

    ?

    一些可以用這個套路解決的題

    暫時就寫這么多啦,作為一個高考語文及格分,大學又學了工科的人,表述能力實在差因此啰啰嗦嗦寫了一大堆,希望大家能理解這個很好用的套路。

    下面我再列舉幾道我在刷題過程中遇到的也是用這個套路秒的題,真的太多了,大部分鏈表和樹的遞歸題都能這么秒,因為樹和鏈表天生就是適合遞歸的結構。

    我會隨時補充,正好大家可以看了上面三個題后可以拿這些題來練練手,看看自己是否能獨立快速準確的寫出遞歸解法了。

    Leetcode 101. 對稱二叉樹

    Leetcode 111. 二叉樹的最小深度

    Leetcode 226. 翻轉二叉樹

    Leetcode 617. 合并二叉樹

    Leetcode 654. 最大二叉樹

    Leetcode 83. 刪除排序鏈表中的重復元素

    ?

    https://mp.weixin.qq.com/s/PgSSYc50ajnbh8zD6Ei07g

    https://mp.weixin.qq.com/s/mJ_jZZoak7uhItNgnfmZvQ

    https://lyl0724.github.io/2020/01/25/1/

    總結

    以上是生活随笔為你收集整理的[递归]递归问题解题思路的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。