递归的定义:在调用一个函数的过程中又出现直接或间接调用该函数本身,称为函数的递归(Recursion)调用,这种函数称为递归函数 。若p函数定义中调用p函数,称之为直接递归。若p函数定义中调用q函数,而q函数定义中又调用p函数,称之为间接递归。
递归的两大要素:
- 递归表达式(递归方程)
- 递归结束条件(边界条件)
能够用递归解决的问题应该满足以下3个条件
- 需要解决的问题可以转化为一个或多个子问题来求解,而这些子问题的求解方法与原问题完全相同,只是在数量规模上不同
- 递归调用的次数必须是有限的
- 必须有结束递归的条件来终止递归
何时使用递归:
- 定义是递归的(阶乘、斐波那契数列等)
- 数据结构是递归的(单链表、二叉树等)
- 问题的求解方法是递归的(汉诺塔、回溯法等)
递归的优缺点:
- 优点:结构清晰,可读性强,而且容易用数学归纳法来证明算法的正确性,因此它为设计算法、调试程序带来很大方便
- 缺点:递归算法的运行效率较低,无论是耗费的计算时间还是占用的存储空间都比非递归算法要多
- 解决方法:在某些递归算法中可消除递归调用,使其转化为非递归算法
阶乘的递归表达式:
斐波拉契数列的递归表达式:
Kimi数列
题目描述
Kimi最近在研究一个数列: * F(0) = 7 * F(1) = 11 * F(n) = F(n-1) + F(n-2) (n≥2) Kimi称之为Kimi数列。请你帮忙确认一下数列中第n个数是否是3的倍数。
输入
输入包含多组数据。 每组数据包含一个整数n,(0≤n≤30)。
输出
对应每一组输入有一行输出。 如果F(n)是3的倍数,则输出“Yes”;否则输出“No”。
public class Main{
public static void main(String[] args) {
// TODO 自动生成的方法存根
Scanner num=new Scanner(System.in);
while(num.hasNext()) {
int n=num.nextInt();
if(func(n)%3==0) {
System.out.println("Yes");
}else {
System.out.println("No");
}
}
System.out.println();
}
public static int func(int n) {
if(n==0) {
return 7;
}else if(n==1) {
return 11;
}else {
return func(n-1)+func(n-2);
}
}
}
递归计数
题目描述
编写一个递归程序,返回一个字符串中大写字母的数目。例如,输入“AbcD”,输出2。
输入
多组输入,每组包括一个仅由大小写字母组成的字符串。
输出
输出字符串中出现大写字母的数目。
样例输入 Copy
AbcD
样例输出 Copy
2
public class Main {
public static void main(String[] args) {
// TODO 自动生成的方法存根
int a;
Scanner str=new Scanner(System.in);
while(str.hasNext()) {
String str1=str.nextLine();
char [] c=str1.toCharArray();
a=c.length;
System.out.println(func(c,a-1));
}
}
public static int func(char [] c,int x) {
if(x==-1) {
return 0;
}else {
if(c[x]>='A'&&c[x]<='Z') {
return 1+func(c,x-1);
}else {
return func(c,x-1);
}
}
}
}
蜂房 问题
题目描述
有一只经过训练的蜜蜂只能爬向右侧相邻的蜂房,不能反向爬行。请编程计算蜜蜂从蜂房a爬到蜂房b的可能路线数。
其中,蜂房的结构如下所示。
输入
多组数据输入,每组数据包含两个正整数a, b,且 a<b。
输出
蜜蜂从蜂房a爬到蜂房b的可能路线数。
样例输入 Copy
1 2 3 4
样例输出 Copy
1 1
public class Main {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Scanner input=new Scanner(System.in);
while(input.hasNext()){
int a=input.nextInt();
int b=input.nextInt();
System.out.println(func(a,b));
}
}
public static int func(int x,int y){
if(x==(y-1)){
return 1;
}
else if(x==(y-2)){
return 2;
}
else return func(x,y-1)+func(x,y-2);
}
}
逆序输出
题目描述
使用递归编写一个程序,逆序输出一个非负整数。例如输入1234,输出4321(不含前导0)。
输入
多组输入,每组输入一个非负整数。
输出
逆序输出结果,每个结果占一行。
样例输入 Copy
12 1230 0
样例输出 Copy
21 321 0
public class Main {
public static int func(int n){
if(n >= 10){
System.out.print(n%10);
n = n/10;
return func(n);
}else {
return n%10;
}
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
while (input.hasNext()){
int n = input.nextInt();
if(n==0){
System.out.println(n);
continue;
} else if(n > 0){
while(n%10==0){
n = n/10;
}
System.out.println(func(n));
}
}
}
}
骨牌覆盖
题目描述
用大小为1×2的骨牌铺满一个大小为2×n的长方形方格,编写一个程序,输入n,输出铺放方案总数。例如,输入n=3,即大小为2×3的方格,输出3。3种骨牌铺放方案如下图所示:
输入
多组测试用例,每一组是一个正整数。
输出
每组输出占一行。
只需要输出铺放方案总数,不需要输出具体的铺放方案。样例输入 Copy
3
样例输出 Copy
3
public class Main {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Scanner num=new Scanner(System.in);
while(num.hasNext()) {
int n=num.nextInt();
System.out.println(function(n));
}
}
public static int function(int n) {
if(n==1) {
return 1;
}else if(n==2) {
return 2;
}else {
return function(n-1)+function(n-2);
}
}
}