递归

递归

1.递归算法及递归函数的概念及其二要素
1.1定义:

​ 1.1 直接或间接地调用自身的算法称为递归算法

1.2 用函数自身给出定义的函数称为递归函数

​ 1.3 由分治法产生的子问题往往是原问题的较小模式,这就为使用递归技术提供了方便:

1.4 在这种情况下,反复应用分治手段,可以使子问题与原问题类型一致而其规模却不断缩小,最终使子 问题缩小到很容易直接求出其解。这自然导致递归过程的产生。

​ 1.5 分治与递归像一对孪生兄弟,经常同时应用在算法设计之中,并由此产生许多高效算法

​ 1.6 两要素:递归方程和边界条件

1.2递归使用场合:

​ ①数据结构本身是递归定义的,其实现算法往往是递归算法,比如二叉树和图等

​ ②求解过程需要递归,算法描述简捷其易于理解及分析,比如阶乘计算

1.3常见使用场景
1.3.1 阶乘函数

public static int recursion(int num){//利用递归计算阶乘

        int sum=1;

        if(num < 0)

            throw new IllegalArgumentException("必须为正整数!");//抛出不合理参数异常

        if(num==1){

            return 1;//根据条件,跳出循环

        }else{

            sum=num * recursion(num-1);//运用递归计算

            return sum;

        }

    }

1.3.2 Fibonacci数列
public class Solution {
    public int Fibonacci(int n) {
        if(n == 0) {
            return 0;
        }
        if(n == 1) {
            return 1;
        }
        return Fibonacci(n-1) + Fibonacci(n-2);
    }
}

1.3.3全排列问题
从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起 叫做从n个不同元素中取出m个元素的一个排   	列,当m=n时所有的  排列情况叫全排列。
  public static void arrange(char[] arr,int left,int right){
        if (left == right){
            System.out.println(Arrays.toString(arr));
        }else{
            for (int i = left ; i <= right; i++) {
                swap(arr, left, i);
                arrange(arr, left + 1, right);
                swap(arr, left, i);
            }
        }
    }
    public static void swap(char[] arr,int i,int j){
        char temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
1.3.4整数划分问题

n=m1+m2+…+mi; (其中mi为正整数,并且1 <= mi <= n),则{m1,m2,…,mi}为n的一个划分。

如果{m1,m2,…,mi}中的最大值不超过m,即max(m1,m2,…,mi)<=m,则称它属于n的一个m划分。这里我们记n的m划分的个数为f(n,m);

举个例子,当n=5时我们可以获得以下这几种划分(注意,例子中m>=5)

5 = 5
= 4 + 1
= 3 + 2
= 3 + 1 + 1
= 2 + 2 + 1
= 2 + 1 + 1 + 1
= 1 + 1 + 1 + 1 + 1

根据n和m的关系,考虑以下几种情况:

  1. 当n=1时,不论m的值为多少(m>0),只有一种划分即{1};
  2. 当m=1时,不论n的值为多少,只有一种划分即n个1,{1,1,1,…,1};
  3. 当n=m时,根据划分中是否包含n,可以分为两种情况:
    (1) 划分中包含n的情况,只有一个即{n};
    (2) 划分中不包含n的情况,这时划分中最大的数字也一定比n小,即n的所有(n-1)划分。因此 f(n,n) =1 + f(n,n-1);
  4. 当n<m时,由于划分中不可能出现负数,因此就相当于f(n,n);
  5. 但n>m时,根据划分中是否包含最大值m,可以分为两种情况:
    (1) 划分中包含m的情况,即{m, {x1,x2,…xi}}, 其中{x1,x2,… xi} 的和为n-m,可能再次出现m,因此是(n-m)的m划分,因此这种划分个数为f(n-m, m);
    (2) 划分中不包含m的情况,则划分中所有值都比m小,即n的(m-1)划分,个数为f(n,m-1);因此 f(n, m) = f(n-m, m)+f(n,m-1);

综合以上情况,我们可以看出,上面的结论具有递归定义特征,其中(1)和(2)属于回归条件,(3)和(4)属于特殊情况,将会转换为情况(5)。而情况(5)为通用情况,属于递推的方法,其本质主要是通过减小m以达到回归条件,从而解决问题。其递推表达式如下:

  • f(n, m)= 1 (n=1 or m=1)

  • f(n, m)=f(n, n) (n<m)

  • 1+ f(n, m-1) (n=m)

  • f(n-m,m)+f(n,m-1) (n>m)


    代码如下 实现语言 java

     public static int division(int n,int m){
            if (n == 1 || m == 1){
                return 1;
            }
            if (n == m) {
                return 1 + division(n, m - 1);
            }
            if (n < m) {
                return division(n, n);
            }
            //最后就是 n > m情况 包含有m划分 和 没有m划分
                return division(n - m , m) + division(n, m - 1);
        }
    
    1.3.5汉诺塔问题

    设a,b,c是3个塔座。开始时,在塔座a上有一叠共n个圆盘,这些圆盘自下而上,由大到小地叠在一起。各圆盘从小到大编号为1,2,…,n,现要求将塔座a上的这一叠圆盘移到塔座b上,并仍按同样顺序叠置。在移动圆盘时应遵守以下移动规则:

    1. 规则1:每次只能移动1个圆盘;
    2. 规则2:任何时刻都不允许将较大的圆盘压在较小的圆盘之上;
    3. 规则3:在满足移动规则1和2的前提下,可将圆盘移至a,b,c中任一塔座上

汉诺塔

思路

​ B为中间塔 C为目标塔只需将A盘前N - 1个盘挪到B盘 将第n个塔挪到C塔,再将B塔所有N - 1个盘借助A塔

​ 移动到C塔即可


代码 使用语言java

/**
 * @Author rwdou
 * @Description 假设起始位置都在a盘塔 有num个盘都移动到c塔
 * @Date 10:57 2020/5/20
 * @Param [num, a, b, c]
 * @return void
**/
    public static void move(int num,char a,char b,char c){
        if (num == 1){
            System.out.println("第一个盘从" + a + "->" + c);
        }else{
            //将上面num - 1个盘移动到中间盘(B盘)
            move(num - 1, a , c, b);
            //将最下面的盘移动到目标塔(C盘)
            System.out.println("第" + num + "个盘移动到" + c + "盘");
            //将num - 1个盘移动到目标盘(c盘)
            move(num - 1, b, a, c);
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值