深入淺出遞歸算法

文章目錄

  • 遞歸思想
  • 遞歸的題目
    • 1.漢諾塔問題
      • 問題分析
      • 代碼展示
    • 2.合并兩個有序鏈表
      • 問題分析
      • 代碼展示
    • 3.反轉鏈表
      • 問題分析
      • 代碼展示
    • 4.兩兩交換 鏈表中的節點
      • 問題分析
      • 代碼展示
  • 總結

在這里插入圖片描述

遞歸思想

遞歸就是將一個很大的問題拆分成子問題,然后再將子問題繼續拆分,拆分成更小的子問題,最后直到不能拆分為止。
遞歸一共分為三個步驟,首先,我們要將一個問題拆為一些子問題,然后去看這些子問題是否有相同的方法可以繼續拆分,所以遞歸的關鍵就是一個大問題是否能轉換成相同類型的子問題,然后子問題是否又能繼續轉換成相同類型的子問題,注意這里我們就需要搞定我們這個遞歸的函數傳遞的參數具體需要什么,也就是(函數頭),當我們確立了子問題之后,我們就需要進行函數體的書寫了,書寫函數體主要圍繞單個子問題進行,因為,我們的一個大的問題都可以拆分為一個個的小的子問題,所以這些子問題都可以通過一個方法來處理,所以只需要對一個子問題進行書寫函數體就行了,最后,我們需要防止無限遞歸,也就是遞歸的終止條件,向上歸的過程。

總結:遞歸的方法

  1. 找到類型相同的子問題
  2. 對某個子問題進行函數體方法的書寫
  3. 遞歸的出口----終止條件的判斷

遞歸的題目

1.漢諾塔問題

問題分析

這里是引用
輸入和輸入:
在這里插入圖片描述

在這里插入圖片描述

首先我們來分析:
1.找到子問題

可以看到子問題很容易就出來了,我們不管有多少個盤子,我們都可以將上面的n-1個盤子看成一個整體,然后將上面n-1個盤子借助C移到B柱上,然后將最下面的盤子移到C上,然后再對上面n-1個盤子實行相同的方法,對上面n-1個盤子上的n-2個盤子用剛剛一樣的方法。

這里子問題找到了,我們就可以確定我們的函數頭和傳遞的參數了,對于上面的圖我們傳遞的函數頭就可以用下面類似方式寫出:dfs(A,B,C,n).
2.用單個子問題尋找函數體
單個子問題是:
在這里插入圖片描述
首先第一步是:dfs(A,C,B,n-1)

這句代碼的意思是將A柱上n-1個盤子從A移到B上,借助C

第二部是:A.back()->C(偽代碼)

將A上最后一個盤子移到C,當我進行了第一步遞歸之后,只剩下最后一個盤子了,所以,我需要將最后一個盤子移到C上

第三部:dfs(B,A,C,n-1)

將B柱上剩下的盤子移到C上,注意中間的過程我們不需要管,他會不斷拆分,我們只需要找到同一的方法即可

3.遞歸出口
對于遞歸的出口,我們可以看上面的子問題,當我們只有一個盤子的時候我們就直降將這個盤子移到C柱上了,所以這里的最后的遞歸出口就是當只有一個盤子的時候。

代碼展示

class Solution {
public:void dfs(vector<int>& x,vector<int>&y,vector<int>&z,int n){if(n==1)//當只有一個盤子的時候移到z柱上{//移到z柱上z.push_back(x.back());//將x柱上的值刪除x.pop_back();return;}//將x柱上的整體的n-1個盤子整體移到y柱上dfs(x,z,y,n-1);//然后將x柱上剩下的一個盤子移動到z柱上z.push_back(x.back());x.pop_back();//最后將y柱上的剩下的盤子移動到z柱上即可,借助x柱,注意:y柱上有n-1個盤子dfs(y,x,z,n-1);}void hanota(vector<int>& a, vector<int>& b, vector<int>& c){dfs(a,b,c,a.size());}
};

2.合并兩個有序鏈表

在這里插入圖片描述
樣例輸入和輸出:
在這里插入圖片描述

問題分析

1.尋找子問題
這里其實我們可以選一個小的作為頭,選好這個頭之后將這個頭去指向這個函數頭,這個函數頭就是去給我們合并的函數。
確定函數頭:dfs(l1,l2)
2.根據單個子問題找到函數體

這里我們可以通過子問題找到函數體:首先函數頭是傳遞兩個鏈表的頭,然后返回的是新的頭結點,所以這里我們只需要取兩個鏈表的中的小的為新的頭,然后去鏈接剩下的兩個鏈表

函數體:min->next=dfs(min->next,other)

這里大致就可以將函數體寫成這樣,小的鏈表的頭指向小的鏈表的剩下的部分和另一個鏈表

3.遞歸出口
遞歸出口:當有一個函數為空時直接返回另一個鏈表,注意:這里其實可以這樣想,當我們鏈接當一個鏈表為空的時候是不是另一個鏈表鏈接上去肯定是有序的,所以這里我們只需要返回另一個部位空的鏈表即可。

代碼展示

class Solution 
{
public:ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {if(list1==nullptr)return list2;if(list2==nullptr)return list1;if(list1->val<=list2->val){list1->next=mergeTwoLists(list1->next,list2);//list1作為頭結點合并list1->next,和list2return list1;}else{list2->next=mergeTwoLists(list1,list2->next);//連接list2->next和list1return list2;}}
};

3.反轉鏈表

在這里插入圖片描述

問題分析

這道題我們其實也可以用遞歸來做,我們要將整個鏈表翻轉其實可以看做將1后面的鏈表翻轉,剩下的鏈表翻轉又可以分解成剩下的鏈表的剩下的部分翻轉,接下來我用一個圖方便理解

在這里插入圖片描述
大概就是上圖的意思,我們先深度優先遍歷到最后一個節點,然后再向上翻轉注意,這里我沒有志向nullptr,但是我們每次翻轉的時候都要指向nullptr,這是為了遞歸的統一。

函數頭
函數頭:dfs(head)

函數體

函數體:newhead=reverseList(head->next);
我們只需要創一個新的頭來等于剩下的翻轉過的鏈表,注意:這里我們翻轉過的鏈表是抽象的遞歸,具體是怎么完成的計算機會完成,我們只需要給出方法,這里我們已經得到了翻轉鏈表的方法之后,我們就可以直接將就的head與翻轉過的鏈表進行連接即可。

遞歸出口
當當前節點指向的下一個是nullptr的時候或者當當前節點是nullptr的時候就直接返回當前節點。

代碼展示

class Solution 
{
public:ListNode* reverseList(ListNode* head) {//出口if(head==nullptr||head->next==nullptr){return head;}ListNode*newhead=reverseList(head->next);//原本head->next是head的next但是現在要反轉過來//就要把head的next節點指向自己就是head->next->next=head;head->next->next=head;head->next=nullptr;return newhead;}
};

4.兩兩交換 鏈表中的節點

這里是引用

問題分析

這里這道題和上一道題其實很相似,我們其實只需要將后面所有應該交換的節點全部交換了,然后將后面節點的新的頭給前面兩個節點連接上即可,注意這里后面是怎么交換的我們也不知道,但是我們用一個函數去讓他交換,我們讓他交換前兩個節點后面剩下的節點,它會轉換成叫喚后面剩下的節點除了前兩個節點外的剩下的節點,這樣一直遞歸下去,直到遇到遞歸出口為止。

函數頭
函數頭:dfs(head)

函數體
注意這里我們返回的交換之后鏈表的新的頭,意思就是當我們把除了1和2節點外的所有節點外的節點交換之后,會返回一個新的節點,注意看上面給出的示例,意思就是當我們用一個遞歸表示的話,返回的就是4這個節點,所以我們可以直接用tmp存儲這個節點,然后將前面兩個節點的指向進行變化即可。
函數體:

ListNode*tmp=swapPairs(head->next->next);
auto next=head->next;
head->next->next=head;
head->next=tmp;

遞歸出口
這里的遞歸出口還是當遇到空節點或者下一個節點是空節點直接返回當前節點

代碼展示

class Solution {
public:ListNode* swapPairs(ListNode* head) {if(head==nullptr||head->next==nullptr){return head;}ListNode*tmp=swapPairs(head->next->next);auto next=head->next;head->next->next=head;head->next=tmp;return next;}
};

總結

遞歸算法作為計算機科學中的一種基本思想,展現了其簡潔優雅和強大的解決問題能力。從數學計算到復雜的數據結構處理,遞歸提供了一種自然且直觀的方法來分解和解決問題。盡管遞歸在某些情況下可能帶來性能和資源上的挑戰,但通過優化技術如記憶化存儲和尾遞歸優化,我們可以克服這些困難,實現高效的遞歸算法。

遞歸不僅僅是編程技術,更是一種思維方式。通過理解遞歸的本質,我們能夠培養出更好的抽象思維能力,解決更復雜的計算問題。希望這篇博客能夠幫助你更好地理解遞歸算法,并激發你在編程中更多地應用和探索這一強大的工具。

無論你是編程新手還是經驗豐富的開發者,掌握遞歸算法都會為你提供一種新的視角,幫助你在算法和數據結構的學習和應用中取得更大的進步。讓我們一起擁抱遞歸的美妙世界,不斷挑戰和提升自我!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/14892.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/14892.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/14892.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

經典正則表達式實例

1、由26個字母組成的字符串 ^[A-Za-z]$2、 由26個字母和數字組成的字符串 ^[A-Za-z0-9]$3、整數形式的字符串 ^-?\d$4、正整數形式的字符串 ^[0-9]*[1-9][0-9]*$5、中國境內郵政編碼,6位 [1-9\d{5}6、匹配中文字符 [\u4e00-\u9fa5]7、國內電話號碼,010-6872**** \d{3}-…

【linux-IMX6ULL-字符設備驅動簡單框架實驗】

目錄 1. 字符設備驅動簡介1.1 重要函數1.2 簡單框架代碼流程1.3 linux中關于驅動的重要命令 2. 字符設備驅動簡單框架編寫2.1 添加LICENSE信息2.2 驅動模塊的入口與出口2.3 入口和出口函數的編寫2.4 設備操作結構體定義2.4.1 結構體函數內容填充 3. 應用程序簡介&#xff1a;4.…

Design to code(2)

【碎碎念】從七點到十一點&#xff0c;累計用時4個小時完成的代碼翻譯Σ(&#xffe3;。&#xffe3;ノ)ノ DCDS圖 順序圖&#xff08;支付過程&#xff09; 交互圖&#xff08;訂單&#xff09; 我的代碼 Payment public class Payment { //定義支付訂單金額 private…

static的了解

【關鍵字】static 使用總結_c static關鍵字-CSDN博客 本文來自上面的文章&#xff0c;這里用于學習&#xff0c;謝謝大佬的分享&#xff01;&#xff01;&#xff01; 非原創&#xff01;&#xff01;&#xff01; 1.一個項目中創建main.cpp和demo.cpp &#xff08;1&#…

FL Studio2025中文最新版本專業編曲軟件有哪些新功能?

FL Studio 21&#xff0c;也被音樂制作愛好者親切地稱為“水果編曲軟件”&#xff0c;是比利時的Image-Line公司研發的一款完整的音樂制作環境或數字音頻工作站&#xff08;DAW&#xff09;。自從1990年代推出以來&#xff0c;FL Studio 以其直觀的用戶界面、豐富的插件支持和強…

Rust分割字符串的常見操作方法

在Rust編程語言中&#xff0c;分割字符串是一個常見的操作&#xff0c;可以通過多種方式實現。以下是一些常用的方法&#xff1a; 使用split方法&#xff1a; split方法可以按照指定的字符或字符序列來分割字符串。它返回一個迭代器&#xff0c;可以迭代分割后的字符串片段。 l…

玩機社區 - 2024年最美社區源碼開源

玩機社區 - 2024年最美社區源碼開源 教程源碼文檔都內置到壓縮包了 https://pan.baidu.com/s/1xwcscTne-JMbmKEntiuAuA?pwd78oi

邏輯分析儀 - 采樣率/采樣深度

采樣深度&#xff08;Sampling Depth&#xff09; 采樣深度指的是邏輯分析儀在一次捕獲過程中可以記錄的最大樣本數量。簡單來說&#xff0c;采樣深度越大&#xff0c;邏輯分析儀可以記錄的數據量就越多。這對于分析長時間的信號變化或復雜的信號序列非常重要。 采樣率&#…

2024年5月23日 (周四) 葉子游戲新聞

《Unclogged》Steam頁面上線 馬桶主題恐怖逃脫解謎Brody制作并發行&#xff0c;一款奇葩創意馬桶主題恐怖逃脫解謎新游《Unclogged》Steam頁面上線&#xff0c;本作暫不支持中文。 Meta人工智能主管楊立昆 大語言模型不會達到人類智能水平IT之家今日&#xff08;5月23日&#x…

QEMU啟動Linux內核

在QEMU環境下啟動linux內核命令如下&#xff1a; QEMU_AUDIO_DRVnone qemu-system-arm -m 256M -nographic -M versatilepb -kernel /home/yukeyang/myfile/linux-6.6.30/arch/arm/boot/zImage -append "consolettyAMA0 rdinit/bin/sh" -dtb arch/arm/boot/dts/arm/…

數據防泄漏系統哪個好用,給文件加密的軟件

數據防泄露&#xff08;Data Leakage Prevention&#xff0c;DLP&#xff09;是指通過一定的技術手段&#xff0c;防止組織指定&#xff08;重要或敏感的&#xff09;數據或信息資產以違反安全策略規定的形式流出組織的一種策略。 信息防泄露以文檔加密技術為核心&#xff0c;…

順序表及其應用

掌握順序表的初始化&#xff0c;初始化、查找、插入、刪除、遍歷、查看實際長度等操作 內容 從鍵盤輸入n個整數&#xff0c;創建順序表。【創建長度為n的順序表】從鍵盤輸入1個整數x&#xff0c;在順序表中查找x所在的位置。若找到&#xff0c;輸出該元素所在的位置(即數組下標…

SQL開窗函數

文章目錄 概念&#xff1a;語法&#xff1a;常用的窗口函數及示例&#xff1a;求平均值&#xff1a;AVG() &#xff1a;求和&#xff1a;SUM():求排名&#xff1a;移動平均計數COUNT():求最大MXA()/小MIN()值求分區內的最大/最小值求當前行的前/后一個值 概念&#xff1a; 開窗…

同旺科技 FLUKE ADPT 隔離版發布 ---- 說明書

所需設備&#xff1a; 1、FLUKE ADPT 隔離版 內附鏈接&#xff1b; 應用于&#xff1a;福祿克Fluke 12E / 15BMax / 17B Max / 101 / 106 / 107 應用于&#xff1a;福祿克Fluke 15B / 17B / 18B

利用文本圖像對比模型進行虛假信息檢測

Harnessing the Power of Text-image Contrastive Models for Automatic Detection of Online Misinformation 論文地址: CVPR 2023 Open Access Repositoryhttps://openaccess.thecvf.com/content/CVPR2023W/WMF/html/Chen_Harnessing_the_Power_of_Text-Image_Contrastive_…

51單片機學習(4)3-1 獨立按鍵控制LED亮滅

#include<REGX52.H> void main() { //P20xFE; P2_01; while(1) { if(P3_10) { P2_00&#xff1b; } else { P2_01&#xff1b; } } }

力扣周賽398題解

特殊數組Ⅰ 如果數組的每一對相鄰元素都是兩個奇偶性不同的數字&#xff0c;則該數組被認為是一個 特殊數組 。 Aging 有一個整數數組 nums。如果 nums 是一個 特殊數組 &#xff0c;返回 true&#xff0c;否則返回 false。 示例 1&#xff1a; 輸入&#xff1a;nums [1] …

SEO:屏蔽流氓蜘蛛抓取

解決屏蔽流氓蜘蛛抓取&#xff0c;如MJ12bot 、DotBot 、BLEXBot 、PetalBot 、DataForSeoBot 1、robots文件屏蔽 User-agent: MJ12bot Disallow: / User-agent:DotBot Disallow: / User-agent:BLEXBot Disallow: / User-agent:PetalBot Disallow: / User-agent:DataForSeoBot…

【C++】<知識點> 標準和文件的輸入輸出

目錄 一、輸入輸出操作 1. 相關的類 2. 標準流對象 3. istream類的成員函數 二、流操縱算子 1. 整數流的基數 2. 浮點數精度的流操縱算子 3. 域寬的流操縱算子 4. 其他的流操縱算子 5. 用戶自定義流操縱算子 三、文件讀寫 1. 文本文件的讀寫 2. 二進制文件的讀寫 3. 文件讀寫…

vue 點擊復制文本到剪貼板

一、首先在vue文件的template中定義復制按鈕 <div size"small" v-if"item.prop jadeCode" class"cell-container"><span>{{ scope.row.jadeCode }}</span> <button click"handleCopy(scope.row.jadeCode)" clas…