zoukankan      html  css  js  c++  java
  • 递归的理解

    对于递归问题,一定要明确的一点是,初始调用该函数时的输入是什么样的;

    • 递归执行的顺序是从后往前(直到递归结束的条件发生),迭代是从前到后;
      • 递归:n!=n*(n-1)! ⇒ 0!=1
      • 迭代:n! ⇒ for i = 1:n: res *= i
    • 递归能够奏效的前提是,问题的规模一定是减少的,或者更为严谨地说,问题一定是朝着递归结束的条件执行的;
    • 递归函数的第一个要执行的就是(if)判断,也即每进入一次递归,都要首先判断是否到达递归的结束,n! ⇒ 0!
    • 其次还要明晰递归函数的功能,是返回某个值,还是对传递进来的数据进行处理(没有返回值)。递归函数内部的第一条语句,也即 if 判断,要根据外部递归函数的返回情况做相应的配套处理;
    • 递归终止时的判断条件,依据的就是递归进行时,传递进去的变化的参数。也即,是对随着递归的进行而发生变化(一般减少,减少到 0,方便做判断,终止条件一般在 0 处,n ⇒ 0)的变量,进行判断;
    • 递归退出的条件,一般都是关于对参数的判断;

    1. 递归的实现

    • 需要传递参数,或者会对全局变量进行修改,总之,递归函数属于更易型函数,不然将会变成无穷循环;

    • 进入函数的第一件事,就是判断,判断是否到达循环终止的条件;

    • 然后是每次递归都要执行的主体部分(调用自己,并传递新的参数进去),此时可以假想为只是一次简单的执行过程,只不过有些值需要需要调用自己才能获得;

    2. 递归 + 动态规划(rec + dp)

    • 递归:需要一次 if 判断,用于判断是否到达递归的终止条件
    • 动态规划:也需要一次 if 判断,用于判断是否是重复计算项(overlapping)
    • 也即结合了递归和动态规划的算法实现,需要隐式地给出两次 if 判断;

    如动态规划+递归实现的斐波那契:

    def fib_rec_dp(n, memo):
        if n <= 0:
            memo[n] = n
            return memo[n]
        try:
            return memo[n]
        except KeyError:
            memo[n] = fib_rec_dp(n-1, memo) + fib_rec_dp(n-2, memo)
            return memo[n]

    3. 递归实现的细节

    分为多步进行,每一步的操纵一模一样,

    • 是否到达终点;
    • 执行必要的操做;

    比如,

    • 棋盘连线的问题,每一步都有四个前进的方向;
    • n 城市的旅行商问题,同样可分为 n 个小操作;

    4. 规模不同,逻辑一致

    • 规模体现在函数的参数;
    • 逻辑一致体现在自己调用自己,函数体一模一样;

    此时便可使用递归;

    比如一个二叉树,它的左子树和右子树,有分别是二叉树,只是规模小了一层,其他一模一样;

    在实际运行时,再次调用自己,函数的参数一定发生变化。

    • 比如通配符字符串匹配问题,w, s ⇒ w’, s’

    5. 递归退出的条件

    • 有返回值:if(….) return …;
    • 无返回值:if(…) return;

    都是在开始部分if() + return ...;退出递归;

  • 相关阅读:
    kafka 的基本概念及使用场景
    使用RedisTemplate执行Redis脚本
    SpringBoot使用Lua脚本操作Redis
    Java不定参数Object… obj 和 Object[] 的区别
    IntelliJ IDEA添加快捷键自动输入@author信息
    使用Guava RateLimiter限流以及源码解析
    go fileserver
    记录了prometheus 告警指标
    https://mp.weixin.qq.com/s/ZBsZHQtAz_vKS8fwvHKB3g图文分析Kubernetes认证、授权和准入控制
    es不停机滚动update
  • 原文地址:https://www.cnblogs.com/mtcnn/p/9424289.html
Copyright © 2011-2022 走看看