• 递归用法总结


    递归定义

    递归调用:在调用一个函数的过程中,这个函数本身又直接或间接地调用了函数本身。
    通俗地说,举个例子。有5个学生在一起,问第5个学生有多少钱,他说比第4个学生多2块,第四个又说比第三个多2块,第三个比第二个多2块,第二个又比第一个多2块。第一个人说自己只有10块。在这个例子中,我们求第5个人有多少钱的时候,可以通过第四个人,第四个通过第三个,一次类推。这就是递归的思想。
    上述求学生钱的例子表达式可以用以下表达式:

        money(5) = money(4) + 2;
        money(4) = money(3) + 2;
        money(3) -= money(2) + 2;
        money(2) = money(1) +2;
        money(1) = 10;
    

    数学公式如下

    money(n) = 10;    (n=1)
    money(n) = money(n-1) + 2; (n>1)
    

    总的来说,递归要有以下两个条件:

    1. 基线条件:也就是停止条件
      2.递归条件:递归关系的表述

    递归的几个经典题目

    斐波那契数列

    斐波那契数列是:0,1,1,2,3,5,8,13,21,34,55,89,144……依次类推下去,你会发现,它后一个数等于前面两个数的和。在这个数列中的数字,就被称为斐波那契数。
    仔细观察我们可以知道,从第三项开始,当前项都等于前两项之和。这就是递归的条件。

    long fac(long n){
       if(n == 1 || n == 0){
                   return n;
        }
       if(n < 0)
            return -1;            //-1代表错误
       
       return fac(n - 1) + fac(n - 2);
    }
    

    阶乘问题

    递归表达式:n! = n * (n-1)!

    long f(int n){
        if( n == 1 || n == 0)
            return 1;
        if(n < 0)
            return -1;
    
        return f(n-1) * n;
    }
    

    汉诺塔问题

    法国数学家爱德华·卢卡斯曾编写过一个印度的古老传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针。印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔。不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金片:一次只移动一片,不管在哪根针上,小片必须在大片上面。僧侣们预言,当所有的金片都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中消灭,而梵塔、庙宇和众生也都将同归于尽。

    简单概述如下:
    有三根杆子X,Y,Z。X杆上有N个(N>1)穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至Y杆:

    1. 每次只能移动一个圆盘;
    2. 大盘不能叠在小盘上面;

    实现如下

    void hanoi(int n,char from,char tmp,char to){
    if (n>0) {
        hanoi(n - 1, from, to, tmp);
        cout<<"take " + n + " from " + from + " to " + to;
        hanoi(n - 1, tmp, from, to);
    }
    }
    

    倒叙输出一个正整数

    说明:给出正整数 n=12345,希望以各位数的逆序形式输出,即输出54321

    递归思想:先输出个位数字,然后在输出个位数字前面的数字,知道没有数字

    代码实现如下:

    void printNum(int n){
         cout << n % 10 << " ";
         if( n > 10){
                printNum(n / 10);
         }
    }
    

    排序问题

    用递归实现:输入一个字符串,打印出该字符串中字符的所有排列。例如输入字符串abc,则输出由字符a、b、c所能排列出来的所有字符串abc、acb、bac、bca、cab和cba。

    递归思想
    假如针对abc的排列,可以分成

    1. 以a开头,加上bc的排列

    2. 以b开头,加上ac的排列

    3. 以c开头,加上ab的排列

      void strfac(string s, int k){

       //递归出口条件:当交换到最后时就输出整个字符串
       if(k == s.length())
       {
           for(int i = 0; i < k; i++){
       	    cout << s[i] << " ";
           }
           cout <<endl;
       }
      
      
       //开始递归的算法
       for(int i = k; i < s.length(); i++){
      
           //将k个字符交换
           char t = s[k];
           s[k] = s[i];
           s[i] = t;
      
           //而后递归调用k+1个字符
           strfac(s,k+1);
      
      
           //回溯后变回原来的字符
           {
       	    char t = s[k];
       	    s[k] = s[i];
       	    s[i]= t;
           }
       }
      

      }

    递归求从 m 个球中摸n个球的排列数

    int getSum(int m,int n){
    
    //判断n 是否大于m
    if(m < n){
    	cout << "摸得球数不能大于球总数" << endl;
    	return 0;
    }
    
    if( m == n)
    	return 1;
    if(n == 0)
    	return 0;
    
    return getSum(m-1,n-1) +getSum(m-1,n);
    
    }
    

    求两个子串的最大公共序列长度

    int getsublen(string s1,string s2){
    
        if(s1.length() == 0 || s2.length() == 0)
    	    return 0;
    
        if(s1.at(0) == s2.at(0))
    	    return getsublen(s1.substr(1),s2.substr(1)) + 1;
        //不相等则子串加一
        else
    	    return max(getsublen(s1.substr(1),s2),getsublen(s1,s2.substr(1)));
    }
    
    int max(int a,int b){
    
        if(a > b)
    	return a;
        else
    	    return b;
    }
  • 相关阅读:
    iOS 8 UIAlertController 和 UIAlertAction
    iOS 利用异常 NSException 调试代码
    iOS 开发 atomic 与 nonatomic 区别
    iOS 9 HTTPS 的配置
    关于Frame加背景的那点事?
    java thread 线程锁同步,锁,通信
    java反射机制
    Java序列化与反序列化
    Java内存分配以及GC
    JavaBean入门笔记
  • 原文地址:https://www.cnblogs.com/zuixime0515/p/10513254.html
Copyright © 2020-2023  润新知