什么是递归
简而言之,就是函数自己调用自己
递归需要满足的条件
- 输入:理解问题的输入是什么
- 终止条件:既然要递归,就需要一直调用自己,这样就需要一个终止条件
- 递归体:找出函数的等价关系式
常见的递归问题
常见的递归问题:Fibonacci数列,阶乘,全排列,整数划分。后续博客在学习的过程中还会继续编辑。每一个具体的问题的思路,详见代码块。
Fibonacci数列
/*
Fibonacci 数列
*/
public class Fibonacci {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
System.out.println(new Fibonacci().getFibonacci(n));
}
public int getFibonacci(int n){
// 输入 n
// 终止条件
if(n == 1) return 1;
if(n == 2) return 2;
//递归关系
return getFibonacci(n-1) + getFibonacci(n-2);
}
}
阶乘问题
/*
阶乘问题
*/
public class Factorial {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
System.out.println(new Factorial().factorial(n));
}
public int factorial(int n){
if(n == 1) return 1;
return n*factorial(n-1);
}
}
全排列
import java.util.Arrays;
/*
全排列
要求解n个数 [N1,N2,...,Nm]的全排列
思路:
1、首先需要思考怎么求 以N1开头的全排列 问题
把N1隔开, N1 | N2, N3, ... ,Nm, 就转换成了 N2, N3, ... ,Nm 全排列问题, 以此类推
2、然后思考怎么求 以 N2/N3/.../Nm 开头的排列呢?
这时候我们交换 N1 和 N2/N3/.../Nm 的位置;
注意:交换位置的时候需要注意力,当交换了N1和N2之后,后面还需要进行N1和N3...的交换
在交换N1和N3之前,需要对N1和N2完成排列之后进行位置的复原。以此类推。
*/
public class AllArrange {
public static void main(String[] args) {
int arr[] = {1,2,3,4};
new AllArrange().allArrange(arr, 0, arr.length);
}
public void allArrange(int[] arr, int start, int end){
if(start == end){
System.out.println(Arrays.toString(arr));
}
else{
for(int i = start; i<end; i++){
// 交换
swap(start, i, arr);
// 剩下的全排
allArrange(arr,start+1, end);
// 交换回来
swap(start, i, arr);
}
}
}
public void swap(int i, int j, int[] arr){
if(i == j) return ;
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
整数划分
import java.util.Scanner;
/*
划分整数
输入:整数 3
输出:
3 = 2 + 1
3 = 1 + 1 + 1
思路: 递归思想;
分析:一个整数 N 的划分中最大的数不超过 M : f(N, M)
可能的情况:
(1) N = 1 :都只有一种划分{1}
(2) M = 1 : 都只有一种划分{1,1, ... ,1}
(3) N > M :
当 划分中有 M 时, 划分就是 M 和 { _, ..., _ } 中的数的和, 显然 { _, ..., _ } 中的数相加为 N-M , 所以转化为了 f(N-M, M) 的问题;
当 划分中没有 M 时, 即划分中最大的数不超过 M-1, 因此可以转化为 1 + f(N, M-1)的问题
(4) N = M :
当 划分中有 M 时, 划分就是{N}, 显然不符合整数划分的题意;
当 划分中没有 M 时, 即划分中最大的数不超过 M-1, 因此可以转化为 f(N, M-1)的问题
(5) N < M :为 f(N, N) 问题
*/
public class DivideInteger {
private static int[] resultStack;
private static int n;
private static int sum = 0;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
DivideInteger divideInteger = new DivideInteger(n);
System.out.println(divideInteger.getDivideNum(n , n-1));
divideInteger.getDivideResult(0, n-1);
}
DivideInteger(int n){
this.n = n;
this.resultStack = new int[n];
}
/*
求所有的划分的结果
*/
public static void getDivideResult(int k, int prior){
if( sum > n) return ;
if( sum == n) {
System.out.print("=");
int i = 0 ;
for(i = 0;i<k-1;i++){
System.out.print( resultStack[i] + "+");
}
System.out.println(resultStack[i]);
}
else {
for(int j = prior; j > 0; j--) {
resultStack[k] = j;
sum += j;
getDivideResult(k + 1, j);
sum -= j; //恢复现场
}
}
}
// 求划分数
public int getDivideNum(int N , int M ){
if( N == 0 || M == 0) return 0;
if( N == 1 || M == 1) return 1;
if( N > M) return getDivideNum(N-M, M) + getDivideNum(N, M-1);
else if( N < M) return getDivideNum(N, N);
else return 1 + getDivideNum(N, M-1);
}
}