《备战蓝桥》之递归(Java)

简介: 本篇文章是针对acwing上的蓝桥杯课程所做的总结,有对应习题与练习,本篇文章主要针对递归常见的模型及对应例题的总结,算法的摩西其实不多,希望能与与大家共同学习,备战蓝桥

知识总结


在蓝桥杯历年真题中,递归与递推考点出现的次数较为高频,最为常见的递归便是斐波那契数列,下边就针对斐波那契数列来总结一下这一类题的做题方法。


我们知道形容1,2,3,5,8,13……这样,后一项等于前两项和的数列就称作斐波那契数列,而这种递归问题都可以抽象出一颗递归搜索树,我们通过递归搜索树这种形象的展示,就可以对递归或递推问题有一定的把握。

我们以求斐波那契数列第六项为例:


 

public static int fab(int n) {
        if(n==1) {
            return 1;
        }else if(n==2) {
            return 2;
        }else
            return fab(n-1)+fab(n-2);
    }
    public static void main(String[] args) {
        Scanner s=new Scanner(System.in);
        int n=s.nextInt();
        System.out.println(fab(n));
    }
    //13


下图为其递归搜索树:


微信图片_20230110180657.png


经典例题

(acwing92)递归实现指数型枚举

原题链接


题解思路:

这一道题就可以将其抽象为一个递归问题,如果有n个数,则每一个数对应两种情况(选或不选),一个数完成后进行下一个数的判断。

可以这n个数的状态用一个长度为n的数组来记录,1表示选,2表示未选,数组遍历进行判断,最后输出结果,完成深度递归后进行回溯。

下图为用例输入3的递归搜索树:


微信图片_20230110180653.png

代码实现:


import java.util.*;
public class Main {
    static int N=16;
    static int[]arr=new int[N];
    //为了使得第几个数与数组的第几个元素相对应,所以数组长度加一
    static int n;
    public static void main(String[]args) {
        Scanner s=new Scanner(System.in);
        n=s.nextInt();
        dfs(1);//从第一个数开始递归
    }
    public static void dfs(int u) {
        if(u>n) {/*当u>n时,意味着整个数组所有元素已经进行了判断
        ,接下来就是遍历数组,根据对应的状态判断其是否需要输出
        */
            for(int i=1;i<=n;i++) {
                if(arr[i]==1) {
                    System.out.print(i+" ");
                }
            }
            System.out.println();
            return;
        }
        arr[u]=2;
        dfs(u+1);
        //该元素状态设为未选,然后递归下一个元素
        arr[u]=1;
        dfs(u+1);
        //该元素状态设为已选,然后递归下一个元素
    }
}


(acwing94)递归实现排列型枚举


原题链接

题解思路:

依次枚举每个位置可以放哪个数,需要参数如下:


  • 1.数组(arr[N])用于存储填入的数据.
  • 2.数组(boolean[N])用于判断某个数字是否可用.
  • 3.目前所在位置.


微信图片_20230110180649.png

代码实现:


import java.util.*;
public class Main {
    static int n;
    final static int N=10;
    static int[]arr=new int[N];
    static boolean []st=new boolean[N];
    //默认为false,所以false为该数字可用,true为不可用
    public static void dfs(int u) {
        if(u>n) {//边界打印
            for(int i=1;i<=n;i++) {
                System.out.print(arr[i]+" ");
            }
            System.out.println();
            return;
        }
        for(int i=1;i<=n;i++) {
            if(!st[i]) {
                arr[u]=i;
                st[i]=true;
                dfs(u+1);
                st[i]=false;//恢复现场
            }
        }
    }
    public static void main(String[]args) {
        Scanner s=new Scanner(System.in);
        n=s.nextInt();
        dfs(1);
    }
}


(acwing93)递归实现组合型枚举

原题链接

题解思路:

题目要求为字典序排序,只要我们按照升序递归,自然输出的即为正确顺序。

下边我们以五个数中取三个数为例,来梳理一下做这类题的思路:


微信图片_20230110180645.png

我们会画出这样一棵递归树,如果要通过代码实现,我们需要通过三个参数。


  • 1是数组(way[N]),用于存储于其中数字,当递归到最后一位时,按序输出数组;
  • 2是递归位置(u),也就是考虑当前位置去存放哪个数;
  • 3是最小开始放置的数字(start),因为题目要求是按序输出,第一个数如果是1,那么第二个数只能是比1大的数


代码实现:


import java.util.*;
public class Main {
    final static int N=30;
    static int[]way=new int[N];
    static int n,m;
    //通过设置全局变量,可以不用传参
    public static void main (String[]args){
        Scanner s=new Scanner(System.in);
        n=s.nextInt();
        m=s.nextInt();
        dfs(1,1);//从第一个位置开始递归,最小开始填入的数也是1
    }
    public static void dfs(int u,int start) {
        //if(u+n-start<m)
        //return;
//上边两行代码实现的是递归树剪枝的过程,当剩余的数字不足以存储在数组内时,可以提前结束递归,提高代码运行效率
        if(u>m) {//边界输出
            for(int i=1;i<=m;i++) {
                System.out.print(way[i]+" ");
            }
            System.out.println();
            return;
        }
        for(int i=start;i<=n;i++) {
            way[u]=i;//从start开始放置数字,保证顺序
            dfs(u+1,i+1);//递归到下一个节点,且strat+1
            way[u]=0;//恢复现场
        }
    }
}

总结


这三种递归模型较为常见,递归可能较难为理解,但各位同学多进行思考、画图,也会慢慢掌握这种模型的。

这篇文章涉及到了指数型排列、全排列和组合型排列三种模型:


  • 指数型排列就是依次枚举每个数字的情况,每个数字有选与不选两种情况,当递归到最底层时,根据判断数组中存储的每个数字选与不选的情况直接从1到n按序输出即可。
  • 全排列是依次枚举每个位置可以放哪个数,设置判断数组判断每个数字是否使用,若为使用将该位置设为该数字,然后递归到下一个位置。
  • 组合型排列也是依次枚举每个位置(共m个位置)放哪个数(但数的范围为start到n),因为要求按字典序,所以后一个数一定比前一个数字大,最后输出数组即可。
相关文章
|
19天前
|
Java
java中递归实例
java中递归实例
23 0
|
2天前
|
Java
Java递归:深入理解与应用
Java递归:深入理解与应用
6 1
|
6天前
|
存储 算法 Java
Java中递归
Java中递归
12 0
|
7天前
|
设计模式 安全 Java
【设计模式】JAVA Design Patterns——Curiously Recurring Template Pattern(奇异递归模板模式)
该文介绍了一种C++的编程技巧——奇异递归模板模式(CRTP),旨在让派生组件能继承基本组件的特定功能。通过示例展示了如何创建一个`Fighter`接口和`MmaFighter`类,其中`MmaFighter`及其子类如`MmaBantamweightFighter`和`MmaHeavyweightFighter`强制类型安全,确保相同重量级的拳手之间才能进行比赛。这种设计避免了不同重量级拳手间的错误匹配,编译时会报错。CRTP适用于处理类型冲突、参数化类方法和限制方法只对相同类型实例生效的情况。
【设计模式】JAVA Design Patterns——Curiously Recurring Template Pattern(奇异递归模板模式)
|
7天前
|
Java
<Java SE> 5道递归计算,创建数组,数组遍历,JVM内存分配...
<Java SE> 5道递归计算,创建数组,数组遍历,JVM内存分配
34 2
|
11天前
|
算法 Java 测试技术
滚雪球学Java(38):探索Java递归的无穷魅力,解决复杂问题轻松搞定
【5月更文挑战第13天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
11 0
滚雪球学Java(38):探索Java递归的无穷魅力,解决复杂问题轻松搞定
|
13天前
|
算法 Java
Java程序设计基础——递归
Java程序设计基础——递归
|
19天前
|
Java C语言
详解java方法与递归
详解java方法与递归
14 3
|
19天前
|
自然语言处理 Java 编译器
【Java探索之旅】方法重载 递归
【Java探索之旅】方法重载 递归
11 0
|
19天前
|
SQL Java 关系型数据库
java 递归返回树形组织结构(附带树形菜单的搜索)
java 递归返回树形组织结构(附带树形菜单的搜索)
31 0