递归学习(Java)

递归的思想

程序调用自身的编程技巧称为递归.。

简单来说,就是一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题(子问题)来求解。因为解决原问题和解决子问题往往是同一个方法,所以形成了自己调用自己的情况。递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。

递归需具备的条件

  1. 子问题须与原始问题为同样的事,且更为简单
  2. 不能无限制地调用本身,必须有个出口,否则会出现栈溢出。

例子: 计算正整数n的阶乘

  1. 原问题: 计算n!
  2. 子问题: 计算(n-1)!
  3. 联系: n!=n*(n-1)!
  4. 出口: n=1时, 结果为1

代码如下:

public class factorial {
    public static void main(String[] args) throws Exception {
        int num = digui(5);
        System.out.println(num);
    }

    public  static  int  digui(int n ) throws Exception {
       if(n<0){
           throw  new Exception("参数不能为负数!");
       }else if(n == 1 || n == 0){ //定义递归的出口
           return 1;
       }else{
           return  n *digui(n-1);
       }
    }

}

递归的过程

在求解n =5的阶乘时,递归过程如下
在这里插入图片描述
我们发现,递归过程和栈的工作原理一致。整个过程实际就是一个栈的入栈与出栈问题,先进后出。

例子:斐波那契数列

斐波那契数列指的是:0、 1、1、2、3、5、8、13…

递归关系表达式: F(n) = F(n-1)+F(n-2), n为>=的整数

代码如下

  public  static  int fib_dg(int n ){
        if(n==0){
            return  0;
        }else if(n==1){
            return 1;
        }else{
            return  fib_dg(n-1)+fib_dg(n-2);
        }
    }

递归的过程

在这里插入图片描述
可以发现,递归一般是自顶向下的形式编写的,比如F(5),向下逐渐分解规模,直到到达了f(1)和f(0)这两个出口,然后逐层返回答案,但是在这个过程中,存在大量的重复计算,导致时间复杂度达到了2^n. 我们以下两种方法解决这个问题

  1. 带有备忘录的递归算法
  2. 自底向上法

带有备忘录的递归算法

直接利用递归求解耗时的原因是重复计算,那么我们可以建立一个【备忘录】,每次算出某个子问题的答案后别急着返回,先记到【备忘录】里再返回,每次遇到一个子问题先去【备忘录】里查一查,如果发现之前已经解决过这个问题了,直接把答案拿出来用,不要再耗时去计算了.

代码如下

public class factorial {

    public  static int[] memo ;
    public static void main(String[] args) throws Exception {
        int n = 20;
        memo = new int[n];
        int fib_dg = fib_dg_memo(20);
        System.out.println(Arrays.toString(memo));
        System.out.println(fib_dg);
    }

    public  static  int fib_dg_memo(int n ){
        if(n==0){
            return  0;
        }else if(n==1){
            return 1;
        }else if(memo[n-1]!=0){
            return memo[n-1];
        }else{
           memo[n-1] =  fib_dg_memo(n-1)+fib_dg_memo(n-2);
           return memo[n-1];
        }
    }
}

通过带有备忘录的递归,我们可以发现运算时间大大减短了。

自底向上法

我们直接从最底下,问题规模最小的F(1)和F(2)开始往上推,直到推到我们想要的答案

代码如下:

public  static void fib_zdxs(int n){
        int[] arr = new int[n];
        if(n<=2) {
            return;
        }
        arr[0] = 1;
        arr[1] = 1;
        for (int i = 2; i <n ; i++) {
            arr[i] = arr[i-1]+arr[i-2];
        }
        System.out.println(Arrays.toString(arr));
    }

自底向上法是最简单的,也是我们最常用的。

总结

  1. 递归运用的场景非常多,比如深度优先遍历,广度优先遍历,树、图
  2. 学好递归,不单单是掌握这一项技能,而是思维的转变。大家抓紧学好递归。
  3. 下篇,我们将来讲动态规划。

引用: 数学建模清风.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值