• 数据机构与算法学习(八)- 递归


    递归需要满足三个条件

    1. 一个问题的解可以分解为几个子问题的解

    2. 这个问题与分解之后的子问题,除了数据规模不同,求解思路完全一致。

    3. 存在递归终止条件

    如何编写递归代码

    最关键的是写出递推公式,找到终止条件,剩下将递推公式转化为代码

    假如有n个台阶,每次可以跨1个台阶或者2个台阶,请问走这n个台阶有哦多少种走法?

    n个台阶的走法就等于先走1台阶后,n-1个台阶的走法加上先走2台阶后,n-2个台阶的走法,用公式表示:

    f(n) = f(n-1) + f(n-2)

    有了递推公式,然后在看终止条件。有1台阶有1种走法,有2个台阶的话,有2中走法。所以

    f(1) = 1
    f(2) = 2

    有了终止条件和递推公式,那么最后转换为代码

    int f(int n){
        if(n == 1) return 1;
        if(n == 2) retrun 2;
        return f(n-1) + f(n-2);
    }

    总结一下,写递归代码的关键就是找到如何将大问题分解为小问题的规律,并且基于此写出递推公式,然后在推敲出终止条件,最后将递推公式和终止条件翻译成代码。

    递归代码的常见问题

    1. 递归代码要警惕堆栈溢出, 函数调用会使用栈来保存临时变量,如果递归很深的话, 一直压栈会有栈溢出风险,一般程序中栈是有大小设置的。

    2. 递归代码要警惕重复计算,像刚才n个台阶的那个例子,假设n=5的话,在n=5时会计算f(4)和f(3),在n=4时会计算f(3)和f(2).这样就有了重复计算。

    递归代码改为非递归代码

    还用n个台阶的例子

    int f(int n){
        if (n ==1 ) return 1;
        if( n == 2) return 2;
    
        int ret = 0;
        int pre = 2;
        int prepre = 1;
        for(int i = 3; i <= n; ++i){
            ret = pre + prepre;
            prepre = pre;
            pre = ret;
        }
        return ret;
    }

    笼统的讲,所有的递归代码都可以改为非递归的迭代循环方式。因为递归本身就是借助栈来实现的,只不过我们使用的栈是系统或者虚拟机本身提供的,我们没有感知罢了。

  • 相关阅读:
    spark 学习笔记 sample 算子
    spark 学习笔记 dataframe注册生成表
    hbase 的hdfs目录解析
    ldap用户创建
    phpldap部署
    ldap部署
    zookeeper 无法启动 ERROR org.apache.zookeeper.server.quorum.QuorumPeer: Unable to load database on disk java.io.EOFException
    数据采集flume kafka
    GraphQL教程(二) .net Core api 2.1
    GraphQL教程(一)。.net Core API2.1
  • 原文地址:https://www.cnblogs.com/OneSky-Mi/p/14620132.html
Copyright © 2020-2023  润新知