算法设计思想(5)— 递归法
1. 遞歸概念
遞歸 Recursion是指在函數(shù)的定義中使用函數(shù)自身的方法,直觀上來看,就是某個(gè)函數(shù)自己調(diào)用自己。
?
遞歸有兩層含義:
- 遞歸問題必須可以分解為若干個(gè)規(guī)模較小、與原問題形式相同的子問題。并且這些子問題可以用完全相同的解題思路來解決;
- 遞歸問題的演化過程是一個(gè)對(duì)原問題從大到小進(jìn)行拆解的過程,并且會(huì)有一個(gè)明確的終點(diǎn)(臨界點(diǎn))。一旦原問題到達(dá)了這個(gè)臨界點(diǎn),就不用再往更小的問題上拆解了。最后,從這個(gè)臨界點(diǎn)開始,把小問題的答案按照原路返回,原問題便得以解決;
簡(jiǎn)而言之,遞歸的基本思想就是把規(guī)模大的問題轉(zhuǎn)化為規(guī)模小的相同的子問題來解決。 在函數(shù)實(shí)現(xiàn)時(shí),因?yàn)榇髥栴}和小問題是一樣的問題,因此大問題的解決方法和小問題的解決方法也是同一個(gè)方法。這就產(chǎn)生了函數(shù)調(diào)用它自身的情況,這也正是遞歸的定義所在。
?
格外重要的是,這個(gè)解決問題的函數(shù)必須有明確的結(jié)束條件,否則就會(huì)導(dǎo)致無限遞歸的情況。總結(jié)起來,遞歸的實(shí)現(xiàn)包含了兩個(gè)部分,一個(gè)是遞歸主體,另一個(gè)是終止條件。
?
寫出遞歸代碼的關(guān)鍵在于,寫出遞推公式和找出終止條件。
?
也就是說我們需要:首先找到將大問題分解成小問題的規(guī)律,并基于此寫出遞推公式;然后找出終止條件,就是當(dāng)找到最簡(jiǎn)單的問題時(shí),如何寫出答案;最終將遞推公式和終止條件翻譯成實(shí)際代碼
?
2. 總結(jié)
遞歸的核心思想是把規(guī)模大的問題轉(zhuǎn)化為規(guī)模小的相似的子問題來解決。
?
在函數(shù)實(shí)現(xiàn)時(shí),因?yàn)榻鉀Q大問題的方法和解決小問題的方法往往是同一個(gè)方法,所以就產(chǎn)生了函數(shù)調(diào)用它自身的情況。另外這個(gè)解決問題的函數(shù)必須有明顯的結(jié)束條件,這樣就不會(huì)產(chǎn)生無限遞歸的情況了。遞歸的應(yīng)用非常廣泛,之后我們要講的很多數(shù)據(jù)結(jié)構(gòu)和算法的編碼實(shí)現(xiàn)都要用到遞歸,例如分治策略、快速排序等等。
?
3. 示例代碼
大家都知道斐波那契數(shù)列,現(xiàn)在要求輸入一個(gè)整數(shù)n,請(qǐng)你輸出斐波那契數(shù)列的第n項(xiàng)(從0開始,第0項(xiàng)為0,第1項(xiàng)是1)。
斐波那契數(shù)列公式為:f[n] = f[n-1] + f[n-2], 初始值f[0]=0, f[1]=1,目標(biāo)求f[n]
使用遞歸:
class Solution {
public:int Fibonacci(int n) {if(n == 0){return 0;}else if(n == 1){return 1;}else {return Fibonacci(n-1) + Fibonacci(n-2);}}
};
不使用遞歸
public class Solution {public int Fibonacci(int n) {int preNum=1;int prePreNum=0;int result=0;if(n==0)return 0;if(n==1)return 1;for(int i=2;i<=n;i++){result=preNum+prePreNum;prePreNum=preNum;preNum=result;}return result;}
}
有一只兔子,從出生后第3個(gè)月起每個(gè)月都生一只兔子,小兔子長(zhǎng)到第三個(gè)月后每個(gè)月又生一只兔子,假如兔子都不死,問每個(gè)月的兔子總數(shù)為多少?
不使用遞歸
#include <iostream>int main()
{int month;while(std::cin >> month){int a = 0;int b = 1;int ret = 0;for(int i=1; i<month; i++){ret = a + b;a = b;b = ret;}std::cout << ret << std::endl;}return 0;
}
使用遞歸
#include<bits/stdc++.h>
using namespace std;
int num_rabit(int month){int res;if(month==1 || month==2 )res=1;elseres=num_rabit(month-1)+num_rabit(month-2);return res;
}
int main(){int month;while(cin>>month){int res=num_rabit(month);cout<<res<<endl;}return 0;
}
?一只青蛙一次可以跳上1級(jí)臺(tái)階,也可以跳上2級(jí)。求該青蛙跳上一個(gè)n級(jí)的臺(tái)階總共有多少種跳法(先后次序不同算不同的結(jié)果)。
class Solution {
public:int jumpFloor(int number) {if(number == 1){return 1;}else if(number == 2){return 2;}else{return jumpFloor(number-1) + jumpFloor(number-2);}}
};
描述
一只青蛙一次可以跳上1級(jí)臺(tái)階,也可以跳上2級(jí)……它也可以跳上n級(jí)。求該青蛙跳上一個(gè)n級(jí)的臺(tái)階(n為正整數(shù))總共有多少種跳法。
示例1
輸入:
3
返回值:
4
因?yàn)閚級(jí)臺(tái)階,第一步有n種跳法:跳1級(jí)、跳2級(jí)、到跳n級(jí)
跳1級(jí),剩下n-1級(jí),則剩下跳法是f(n-1)
跳2級(jí),剩下n-2級(jí),則剩下跳法是f(n-2)
所以f(n)=f(n-1)+f(n-2)+…+f(1)
因?yàn)閒(n-1)=f(n-2)+f(n-3)+…+f(1)
所以f(n)=2*f(n-1)
class Solution {
public:int jumpFloorII(int number) {if(number == 1){return 1;}else if(number == 2){return 2;}else{return jumpFloorII(number-1) * 2;}}
};
總結(jié)
以上是生活随笔為你收集整理的算法设计思想(5)— 递归法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2022-2028年中国快捷酒店行业市场
- 下一篇: 2022-2028年中国香薰行业市场研究