《备战蓝桥》之递归(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),因为要求按字典序,所以后一个数一定比前一个数字大,最后输出数组即可。
相关文章
|
2月前
|
Java
java基础(11)函数重载以及函数递归求和
Java支持函数重载,即在同一个类中可以声明多个同名方法,只要它们的参数类型和个数不同。函数重载与修饰符、返回值无关,但与参数的类型、个数、顺序有关。此外,文中还展示了如何使用递归方法`sum`来计算两个数之间的和,递归的终止条件是当第一个参数大于第二个参数时。
32 1
java基础(11)函数重载以及函数递归求和
|
4月前
|
算法 Java
java使用递归及迭代方式实现前序遍历 中序遍历 后序遍历 以及实现层序遍历
java使用递归及迭代方式实现前序遍历 中序遍历 后序遍历 以及实现层序遍历
86 7
|
5月前
|
Java
蓝桥杯Java组暴力递归搜图
蓝桥杯Java组暴力递归搜图
33 4
|
5月前
|
Java
java实现斐波那契数列(递归、迭代、流)
java实现斐波那契数列(递归、迭代、流)
|
5月前
|
算法 前端开发 Java
探讨Java中递归构建树形结构的算法
探讨Java中递归构建树形结构的算法
72 1
|
5月前
|
存储 Java
Java基础手册(标识符 关键字 字面值 变量 数据类型 字符编码 运算符 控制语句 方法及方法重载和递归 面向对象与面向过程)
Java基础手册(标识符 关键字 字面值 变量 数据类型 字符编码 运算符 控制语句 方法及方法重载和递归 面向对象与面向过程)
39 0
|
5月前
|
Java 大数据 程序员
老程序员分享:java递归
老程序员分享:java递归
28 0
|
5月前
|
Java
二分查找-递归(java)
二分查找-递归(java)
|
5月前
|
Java
java使用递归遍历文件目录
java使用递归遍历文件目录
|
5月前
|
Java
杭电acm2018 母牛的故事 Java解法 经典递归
杭电acm2018 母牛的故事 Java解法 经典递归
27 0
下一篇
无影云桌面