递归算法
-
递归算法是一种从自顶向下的算法 ,实际上是通过不停的直接调用或者间接的调用自身的函数,通过每次改变变量完成多个过程的重复计算,直到到达边界之后,结束调用。
-
与递推法相似的是,递归与递推都是将一个复杂过程分解为几个简单重复步骤进行计算。
-
实现的核心是分治策略,即分而治之,将复杂过程分解为规模较小的同类问题,通过解决若干个小问题,进而解决整个复杂问题。
-
递归算法设计的一般步骤:
- 根据题目设计递归函数中的运算部分;
- 根据题目找到递归公式,题目可能会隐含给出,也可能需要自己进行推导;
- 找到递归出口,即递归的终止条件。
递推算法(迭代)
- 一个问题的求解需要大量重复计算,在已知的条件和所求问题之间总存在着某种相互联系的关系,在计算时,我们需要找到这种关系,进行计算(递推关系式)。
- 即递推法的关键,就是找到递推关系式,这种处理方式能够将复杂的计算过程,转化为若干步骤的简单重复运算。
例题1:
题目描述:
斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”。
指的是这样一个数列:0、1、1、2、3、5、8、13、21、34、……
在数学上,斐波那契数列以如下被以递推的方法定义:F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*)
请求出该数列中第n个数字(n从1开始计数)是多少。
样例:
输入样例
样例输入
6
输出
8
对应的计算过程:
[0]=0
[1]=1
[2]=0+1
[3]=1+1=2
[4]=1+2=3
[5]=2+3=5
[6]=5+3=8
题目解析:
-
递归式,F(n)= F(n-1) + F(n-2)
-
F(n)=0 n=0 ,F(n)=1 n=1 这就是递归出口,能让递归停止的条件。
递推法实现:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
int n; //第几个数
int x=0; //F(n)
int y=1; //F(n+1)
int ans = 0; //F(n+2)
Scanner in = new Scanner(System.in);
n = in.nextInt();
if(n==0) ans=0;
else if(n==1) ans=1;
else {
for(int i=2;i<=n;i++)
{
ans=x+y;
x=y;
y=ans;
}
}
System.out.println(ans);
}
}
递归法实现:
import java.util.Scanner;
public class Main {
static int fn(int n)
{
if(n==0)
return 0;
//递归出口2
else if(n==1 )
return 1;
else
return fn(n-1)+fn(n-2); //递归关系式
}
public static void main(String[] args) {
int n; //第几个数
int ans = 0;
Scanner in = new Scanner(System.in);
n = in.nextInt();
ans=fn(n);
System.out.println(ans);
}
}
例题2: (题目分存储和非存储的,若是需要多次询问数据,就采取存储的方式)
题目描述:
这样一个数列:0、1、1、2、3、5、8、13、21、34、……
在数学上,斐波那契数列以如下被以递推的方法定义:F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*)。
我们将进行M次查询,每次输入一个N,其中n小于30。
请求出该数列中第n个数字(n从1开始计数)是多少?
样例:
输入样例
样例1输入:
6
4
2
7
8
8
10
输出样例
样例1输出:
3
1
13
21
21
55
题目解析:
这道题跟上面一道题的算法原理相同,只是增加了多次查询的复杂度;
将每次访问的结果都保存在数组中,数组的下标正好与n对应起来
数组的长度就是n的取值范围;
递推法实现:
import java.util.Scanner;
public class DiGui1 {
//将每次访问的结果都保存在数组中,数组的下标正好与n对应起来
static int[] result = new int[35];
//实现每次计算
static void danci() {
result[0] = 0;
result[1] = 1;
for(int i=2;i<=30;i++) {
result[i] = result[i-1] + result[i-2];
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int m = scanner.nextInt();//m次的查询
danci(); //因为此函数不需要传参数,运行一次,就将n从0到30的结果都保存到结果数组中,所以写到每次循环的外面
//查询m次
while(m>0) {
m--;
//要查询的值对应的n,在循环体内输入
int n = scanner.nextInt();
System.out.println(result[n]);
}
}
}
递归法实现:
import java.util.Scanner;
public class DiGui2 {
// 将每次访问的结果都保存在数组中,数组的下标正好与n对应起来
static int[] result = new int[35];
// 实现每次计算
static int danci(int n) {
// 递归出口1
if (n == 0) {
result[0] = 0;
return 0;
} else if (n == 1) {
result[1] = 1;
return 1;
} else {
result[n] = danci(n - 1) + danci(n - 2);
return result[n];
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int m = scanner.nextInt();// m次的查询
// 因为递归底层运算是从n=0 一直到n=30,运行一次,就将n从0到30的结果都保存到结果数组中,所以写到每次循环的外面
danci(30);
// 查询m次
while (m > 0) {
m--;
// 要查询的值对应的n,在循环体内输入
int n = scanner.nextInt();
System.out.println(result[n]);
}
}
}
总结:
对于以上两种方式实现存储型的递推与递归,都是先把各个结果得出,存储到数组中保存起来,那多次访问,就不用每次都计算一下。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!