常见的递归问题(Fibonacci数列,阶乘,全排列,整数划分)

什么是递归

简而言之,就是函数自己调用自己

递归需要满足的条件

  • 输入:理解问题的输入是什么
  • 终止条件:既然要递归,就需要一直调用自己,这样就需要一个终止条件
  • 递归体:找出函数的等价关系式

常见的递归问题

常见的递归问题: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);
    }
}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值