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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

【☀️~爆肝万字总结递归~❤️玩转算法系列之我如何才能掌握递归解题的能力❤️~十大经典问题助你突破极限~建议收藏☀️】

發布時間:2024/10/5 编程问答 26 豆豆

🍅 作者主頁:Roninaxious
🍅 歡迎點贊 👍 收藏 ?留言 📝

🚢前言

🎐何為遞歸

遞歸顧名思義就是′遞′′歸′

👀所謂的‘遞’也就是“向下遞去”,這個問題可以分解為若干個且形式相同的子問題,這些子問題可以使用相同的思路來解決。

👀所謂的‘歸’也就是“歸來的意思”,什么時候歸來?所以涉及到了臨界點,也就是‘遞’中的分解終止條件。


🎐遞歸的工作原理

💦根據遞歸兩字的含義,不難發現,它包含了遞去和歸來兩個層面。


💦根據以上分析可以發現這個流程和棧的工作原理一致,遞歸調用就是通過棧這種數據結構完成的。整個過程實際上就是一個棧的入棧和出棧問題。然而我們并不需要關心這個棧的實現,這個過程是由系統來完成的。

🎐遞歸 == 數學歸納法 ?

眾所周知,計算機是數學的一個分支。這是一個不可否認的問題,在編程過程中,我們總能在數學中找到答案。遞歸提高了代碼的可讀性,但同時加大了內存的消耗,遞歸讓人又愛又恨;不可否認,遞歸很重要!那么它和數學歸納法有什么聯系呢?

💦歸納法
對于一個命題S(n),n為大于0的自然數;如何證明命題成立呢?

👀1.當n=1時,命題成立
👀2.當n=k時,命題成立
👀3.證明n=k+1時命題也成立

🧧遞歸本質上是類似歸納法,但又有點稍微不同🧧

遞歸是從F(n)倒推到F(1),然后在F(1)回溯到F(n);相比于歸納法多了一步。

💟 對于遞歸你了解多少了呢?💟

  • 🚢前言
    • 🎐何為遞歸
    • 🎐遞歸的工作原理
    • 🎐遞歸 == 數學歸納法 ?
  • 🚢如何正確使用遞歸
    • 🎐遞歸常用流程
    • 🎐遞歸的三大要素
      • 💥1、縮小問題規模
      • 💥2、明確遞歸終止條件
      • 💥3、給出遞歸終止時的處理辦法
  • 🚢經典問題一之迷宮求解
    • 🎐迷宮求解流程分析
    • 🎐源代碼
  • 🚢經典問題二之鏈表反轉一(全反轉)
    • 🎐鏈表反轉流程分析
    • 🎐源代碼
  • 🚢經典問題二之鏈表反轉二(反轉前n個節點)
    • 🎐鏈表反轉2流程分析
    • 🎐源代碼
  • 🚢經典問題二之鏈表反轉三(反轉中間部分)


🚢如何正確使用遞歸

使用遞歸需要注意很多點,否者造成無限遞歸?就是在造孽了

🎐遞歸常用流程

* void func(mode)* {* if(endCondition) //臨界條件* {* constExpression //處理方法* }* else* {* accumrateExpreesion //歸納項* mode=expression //步進表達式* func(mode) //調用本身,遞歸* }* }

🙄注意一定不要在自己腦子里遞來遞去的,你的腦子能壓幾個棧呢,否者很容易就陷入死腦筋之中🙄

🎐遞歸的三大要素

💥1、縮小問題規模

👀這個縮小問題規模可以根據歸納法先進行回推,比如讓求S(n),我們可以先求當n=1的解決方法,再求n=2時的解決方法…一直歸納到S(n);這樣我們就可以推導出關系式S(n)=S(n-1)+?

稍后會根據經典問題思考如何縮小問題規模。

💥2、明確遞歸終止條件

👀遞歸既然有去有回,就必須有一個臨界條件,當程序到達這個臨界值就必須進行歸來;否者就肯定會造成無線遞歸下去,什么棧也扛不住!

💥3、給出遞歸終止時的處理辦法

👀根據上文中闡述的遞歸的工作原理,遞歸是通過棧來實現的;當程序到達臨界條件時,后續必須進行出棧。了解函數的壓棧和出棧過程,函數出棧也就是返回到上一個函數的調用處繼續執行。例如求解F(n),遞推式是F(n)=F(n-1)+F(n-2),終止條件F(1)=1,F(0)=0;它的流程是每次進行壓棧F(n-1)、F(n-2),當達到終止條件時進行函數的出棧,那么返回什么值呢?根據遞歸的倒數第一步F(2)=F(1)+F(0)所以返回的是F(1)+F(0),也就是1.


🚢經典問題一之迷宮求解

?問題描述?

  • 找到迷宮路出口

🎐迷宮求解流程分析

右下角為迷宮的出口,方塊為墻,圓形塊為迷宮入口;如何找到一條通路從入口到出口?


🎈為了表示方便,我以二位數組為例進行操作。擬定二位數組中的1代表墻,2代表通路,3代表路已經走過且不通,0代表未走過的路。

?? 初始化迷宮

📑首先迷宮有四個方向可以走(上下左右),所以我們應該先自定義一個策略,規定?下右上左?(優先走下,然后右->上->左),也就是當下不通時,走右…

🎆根據遞歸三要素

1.分解成子問題

2.遞歸終止條件

這個當然就是出口了,也就是map[5][6] == 2;

🎐源代碼

public class Labyrinth {private static final int X_MAX = 7;private static final int Y_MAX = 8;private static int[][] map = new int[X_MAX][Y_MAX];/*** 迷宮問題--遞歸* 思路:* 策略:規定下右上左為行走策略* 1代表障礙物,2代表走過的路,3代表路已經走過且不通,0代表未走過的路*/public static boolean setWays(int[][] arr, int x, int y) {if (arr[5][6] == 2) { //終止條件return true;} else {if (arr[x][y] == 0) {arr[x][y] = 2;if (setWays(arr, x, y + 1)) { //下return true;} else if (setWays(arr, x + 1, y)) { //右return true;} else if (setWays(arr, x, y - 1)) { //上return true;} else if (setWays(arr, x - 1, y - 1)) {//左return true;} else { //如果下右上左都不能走,所以此路不同,置為3arr[x][y] = 3;return false;}} else { //arr[x][y] != 0 ? 有可能是1,2,3return false;}}}//測試public static void main(String[] args) {for (int i = 0; i < X_MAX; i++) {map[i][0] = 1;map[i][Y_MAX - 1] = 1;}for (int j = 1; j < Y_MAX - 1; j++) {map[0][j] = 1;map[X_MAX - 1][j] = 1;}map[1][2] = 1;map[1][3] = 1;map[2][3] = 1;map[3][3] = 1;map[3][2] = 1;setWays(map, 1, 1);printMap(map);}//打印迷宮地圖public static void printMap(int[][] arr) {for (int j = 0; j < Y_MAX; j++) {for (int i = 0; i < X_MAX; i++) {System.out.print(arr[i][j] + " ");}System.out.println();}} }

?? 運行結果


🚢經典問題二之鏈表反轉一(全反轉)

🔰問題描述🔰

  • 給定一個鏈表,將其反轉
  • 例如:1->2->3->4 ---- 4->3->2->1

🎐鏈表反轉流程分析

📑對于該問題,將其整體分為兩部分1和n-1,將其反轉即可;然后再將n-1部分整體分為兩部分,再將其反轉即可。

🎆根據遞歸三要素

1.分解成子問題

2.遞歸終止條件

對于這個終止條件,這個應該比較簡單,當遞歸到最后一個節點時開始進行歸來操縱,也就是head.next == null || head == null;對于這個head == null是因為空鏈表的情況。

3.遞歸終止處理辦法

由于我們最后反轉鏈表之后,要將最后一個節點定義為頭節點。所以需要將該節點返回。

if (head == null || head.next == null) {return head;}

🎐源代碼

package com.zsh.algorithm.recursion;/*** @author:Ronin* @since:2021/9/16* @email:1817937322@qq.com*//*** 反轉單鏈表 question one* eg:1->2->3->4 ---- 4->3->2->1*/ public class ReverseLinkedList {/*** 鏈表反轉* 思路:將鏈表分成兩部分(1.第一個頭節點 2.頭節點之后的所有)* 遞歸回溯時將指針反轉即可* 遞歸出口條件:head || head.next == null* @param head* @return*/static Node reverse(Node head) {if (head == null || head.next == null) {return head;}Node currentNode = reverse(head.next);head.next.next = head;head.next = null;return currentNode;}// public static void main(String[] args) { // Node node = new Node(1); // Node node2 = new Node(2); // Node node3 = new Node(3); // LinkedListNode linkedListNode = new LinkedListNode(); // linkedListNode.add(node); // linkedListNode.add(node2); // linkedListNode.add(node3); // Node reverseHead = reverse(linkedListNode.head); // linkedListNode.print(reverseHead); // } }//class Node { // int num; // Node next; // public Node() {} // public Node(int i) { // this.num = i; // } //} //class LinkedListNode { // Node head = null; // // public void add(Node addNode) { // if (head == null) { // head = addNode; // return; // } // Node temp = head; // while (temp.next != null) { // temp = temp.next; // } // temp.next = addNode; // temp = addNode; // temp.next = null; // } // // public void print(Node reverseHead) { // Node temp = reverseHead; // while (temp != null) { // System.out.print(temp.num); // System.out.print("->"); // temp = temp.next; // } // } //}



🚢經典問題二之鏈表反轉二(反轉前n個節點)

🔰問題描述🔰

  • 反轉單鏈表2
  • 反轉前n個節點 1->2->3->4->5->6
  • reverse(node head, 3)
  • 3->2->1->4->5->6

🎐鏈表反轉2流程分析

如果已經了解了全部節點的鏈表反轉,那么這個應該也比較簡單;反轉前n個節點,當然就是臨界條件改變了。全部節點的反轉是在最后一個節點作為臨界值,而這個只需要加入一個新的變量n進行控制前n個節點反轉即可。

下圖是出棧得流程

🎐源代碼

public class ReverseLinkedListFront {static Node cur = null;static Node reverse(Node head, int n) {if (n <= 1 || head.next == null) {cur = head.next;return head;}Node lastNode = reverse(head.next, n-1);head.next.next = head;head.next = cur;return lastNode;}// public static void main(String[] args) { // Node node = new Node(1); // Node node2 = new Node(2); // Node node3 = new Node(3); // LinkedListNode linkedListNode = new LinkedListNode(); // linkedListNode.add(node); // linkedListNode.add(node2); // linkedListNode.add(node3); // Node reverseHead = reverse(linkedListNode.head, 3); // linkedListNode.print(reverseHead); // } }

🚢經典問題二之鏈表反轉三(反轉中間部分)

對于1->2->3->4->5,我們將m=2,n=4進行反轉
結果1->4->3->2->5

思路:
1.對于反轉(m~n),如果m=1也就是前n個節點反轉。
2.frontHead.next = reverse(frontHead.next, m-1, n-1);這一行代碼是最難理解的。m-1代表每次frontHead.next,當m=1時,就到達了鏈表反轉部分的起點;n-1是因為(例如m=2,n=5,只反轉n-m=3個節點)。
3.return reverse(frontHead, n);會將中間(m~n)個節點進行反轉
4.在第三步遞歸結束之后會返回到這一步frontHead.next =reverse(frontHead.next, m-1, n-1); 開始從m=3進行回溯,直到m=1.回溯時進行連接
5.該題非常考驗遞歸解題能力.

public class ReverseLinkedListMid {static Node cur = null;static Node reverse(Node frontHead, int m, int n) {if (m == 1) {/*** 將局部進行反轉,并與尾節點部分進行連接*/return reverse(frontHead, n);}/*** 1-》2-》3-》4-》5 ==》 1-》2-》4-》3-》5* 在上一步【return reverse(frontHead, n)】返回的是反轉之后的頭節點,也就是4節點* 這一步是為了將2節點連接4、1節點連接2...*/frontHead.next = reverse(frontHead.next, m-1, n-1);return frontHead;}//局部反轉方法static Node reverse(Node head, int n) {if (n == 1 || head.next == null) {cur = head.next;return head;}Node lastNode = reverse(head.next, n - 1);head.next.next = head;head.next = cur;return lastNode;}public static void main(String[] args) {Node node = new Node(1);Node node2 = new Node(2);Node node3 = new Node(3);Node node4 = new Node(4);Node node5 = new Node(5);LinkedListNode linkedListNode = new LinkedListNode();linkedListNode.add(node);linkedListNode.add(node2);linkedListNode.add(node3);linkedListNode.add(node4);linkedListNode.add(node5);Node reverseHead = reverse(linkedListNode.head, 3, 4);linkedListNode.print(reverseHead);} }

飛速總結中…

與50位技術專家面對面20年技術見證,附贈技術全景圖

總結

以上是生活随笔為你收集整理的【☀️~爆肝万字总结递归~❤️玩转算法系列之我如何才能掌握递归解题的能力❤️~十大经典问题助你突破极限~建议收藏☀️】的全部內容,希望文章能夠幫你解決所遇到的問題。

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