【Java】/*方法的递归*/

目录

一、递归的概念

二、递归执行过程分析

三、递归练习

[3.1 按顺序打印一个数字的每一位,例如123打印出1 2 3](#3.1 按顺序打印一个数字的每一位,例如123打印出1 2 3)

[3.2 递归求 1 + 2 + 3 + ... + n 的和](#3.2 递归求 1 + 2 + 3 + ... + n 的和)

[3.3 输入一个非负整数,返回组成它的数字之和,例如123,得1+2+3](#3.3 输入一个非负整数,返回组成它的数字之和,例如123,得1+2+3)

[3.4 求斐波那契数列的第 N 项](#3.4 求斐波那契数列的第 N 项)


一、递归的概念

  1. 生活中例子:

从前有坐山,山上有座庙,庙里有个老和尚给小和尚将故事,讲的就是:

"从前有座山,山上有座庙,庙里有个老和尚给小和尚讲故事,讲的就是:

"从前有座山,山上有座庙..."

"从前有座山......" "

像这种自身中又包含了自己的现象,在数学和编程中非常有用,因为有些时候,我们遇到的问题直接并不好解决,但是会发现将原问题拆分成其子问题之后,子问题与原问题有相同的解法,这样的话子问题解决之后,原问题也就会迎刃而解了。

  1. 递归的概念:一个方法在执行过程中调用自身,就称为 "递归",与上面生活中的例子不同的是,递归不是无限递归,它必须有一个递归结束的条件。

  2. 在程序层面要完整的写出一个递归需要两个必备的条件:

① 起始条件:可以理解为递归结束的条件

递归公式:每个问题的递推公式是不一样的,例如求N!,可以转换成求 N+(N-1)!

  1. 递归的缺点:空间复杂度高,能用迭代的就不要用递归

二、递归执行过程分析

  1. 要想弄清楚递归执行的过程,通常会通过画图的方式进行理解,下面以求N!为例进行分析

  2. 思路:假如要求3!,通过分析我们可以将其拆分为求3*2!,而2!又可以拆分为求2*1!,很明显可以看出我们在做一件重复的事,即求一个数的阶乘里面又可以看成求一个数的阶乘,而我们知道1!=1,因此这道题是满足使用递归所需的两个必备条件的,所以可以采用递归的方式进行求解。

  3. 求解的代码思路为,定义一个求阶乘的方法,如果n==1,就返回1,否则返回n*fac(n-1),递归执行的过程,见下图图片所示。

java 复制代码
    public static int fac(int n) {
        if (n == 1) {
            return 1;
        }
        return n * fac(n - 1);
    }

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        System.out.println(fac(n));
    }

三、递归练习

3.1 按顺序打印一个数字的每一位,例如123打印出1 2 3

思路:打印123的每位,可以看成先打印12(123/10)的每位,再打印3(123%10),打印12的每位可以看成先打印1(12/10)的每位,再打印2(12%10),而我们知道当要打印的数为小于10的数时,直接打印即可,这道题是满足使用递归所需的两个必备条件的,所以可以采用递归的方式进行求解。

求解的代码思路:定义一个求打印一个数字每位的方法,如果n < 10,直接打印并返回,否则返回n*printNum(n-1),递归执行的过程,见下图图片所示。

java 复制代码
    public static void printNum(int n) {
        if (n < 10) {
            System.out.printf("%d ", n);
            return;
        }
        printNum(n / 10);
        System.out.printf("%d ", n % 10);
    }

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        printNum(n);
    }

3.2 递归求 1 + 2 + 3 + ... + n 的和

思路:当n=3时,表示我们要求3~1之间整数的和,这个式子又可以看成3加2~1之间整数的和,2~1之间整数的和又可以看成求2加1~1之间整数的和,而1~1之间整数的和就是1,这道题是满足使用递归所需的两个必备条件的,所以可以采用递归的方式进行求解。

求解的代码思路:定义一个求n~1之间整数和的方法,如果n == 1,直接返回1,否则返回n+addNum(n-1),递归执行的过程,见下图图片所示。

java 复制代码
    public static int addNum(int n) {
        if (n == 1) {
            return 1;
        }
        return n + addNum(n - 1);
    }

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        System.out.println(addNum(n));
    }

3.3 输入一个非负整数,返回组成它的数字之和,例如123,得1+2+3

思路:假设我们要求组成123每一位数字的和,可以看成求3(123%10)加组成12(123/10)每一位数字的和,求组成12每位数字的和,又可以看成求2(12%10)加组成1(12/10)每一位数字的和,当我们要求的和的数小于10时直接返回即可,这道题是满足使用递归所需的两个必备条件的,所以可以采用递归的方式进行求解。

求解的代码思路:定义一个求组成某数字的每位和的方法,如果n < 1,直接返回n,否则返回 n%10 + numAdd(n/10),递归执行的过程,见下图图片所示。

java 复制代码
    public static int numAdd(int n) {
        if (n < 10) {
            return n;
        }
        return n % 10 + numAdd(n /10);
    }

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        System.out.println(numAdd(n));
    }

3.4 求斐波那契数列的第 N 项

什么是斐波那契数列:斐波那契数列 - 搜狗百科 (sogou.com),指的是这样一个数列:0、1、1、2、3、5、8、13、21、34、......,即从第3项开始,每一项都等于前两项之和。

思路:如果我们要求斐波那契数的第n项,那么求得斐波那契数的第n-1项和n-2项之和即可,而求斐波那契数的第n-1项,又可以看作求斐波那契数的第n-2项和n-3项之和...,如果n为1则直接返回0即可,如果n为2则直接返回1即可,这道题是满足使用递归所需的两个必备条件的,所以可以采用递归的方式进行求解。

求解的代码思路:定义一个求斐波那契数第n项的方法,如果n == 1,直接返回0,否则如果n == 2返回1,否则返回 fib(n-1) + fib(n -2),递归执行的过程,见下图图片所示。

java 复制代码
    public static int fib(int n) {
        if (n == 1) {
            return 0;
        } else if (n == 2) {
            return 1;
        }
        return fib(n - 1) + fib(n - 2);
    }

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        System.out.println(fib(n));
    }

但当我们求 fib(40) 的时候发现, 程序执行速度极慢,原因是进行了大量的重复运算,如在上面基础上加上一个成员变量,当n=40时,记录fib(1)一共计算了多少次,结果为39088169次。因此本道题不适合用递归的方式求,而更适合用迭代的方式求。

java 复制代码
    public static int count = 0;//成员变量,实现累加
    public static int fib(int n) {
        if (n == 1) {
            count++;
            return 0;
        } else if (n <= 2) {
            return 1;
        }
        return fib(n - 1) + fib(n - 2);
    }

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        System.out.println(fib(n));
        System.out.println(count);
    }

(以后求斐波那契数列的第 N 项都用迭代的方法)

**思路:**我们可以定义fib3、fib2、fib1分别表示要求的第n项,和第n-1项、第n-2项,如果是要求第1项或第2项的斐波那契数,特殊处理返回即可;当n>=3时,n-2等于几就执行几次求 fib3 和更新fib1、fib2的操作,循环结束后fib3就是斐波那契数列的第n项项的值。

java 复制代码
    public static int fib2(int n) {
        int f1 = 0;
        int f2 = 1;
        int f3 = 1;
        /*前两项特殊处理*/
        if (n == 1) {
            return 0;
        } else if (n == 2){
            return 1;
        }
        /* n>=3时 */
        for (int i = 3; i <= n; i++) {
            f3 = f1 + f2;
            f1 = f2;
            f2 = f3;
        }
        return f3;
    }

本篇文章已完结,谢谢支持哟 ^^ !!!

相关推荐
灰色人生qwer1 分钟前
内网服务器centos7安装jdk17
java·运维·服务器
ゞ 正在缓冲99%…3 分钟前
leetcode221.最大正方形
java·算法·动态规划
五行星辰3 分钟前
Java HttpURLConnection修仙指南:从萌新到HTTP请求大能的渡劫手册
java·开发语言·http
_x_w4 分钟前
【8】数据结构的栈与队列练习篇章
开发语言·数据结构·笔记·python·链表
cg50177 分钟前
Spring Boot 中的 Bean
java·前端·spring boot
anan4668 分钟前
基于langchain的长文本多迭代总结
java
阮瑭雅9 分钟前
Java语言的Web安全
开发语言·后端·golang
努力也学不会java11 分钟前
【动态规划】深入动态规划 非连续子序列问题
java·数据结构·算法·leetcode·动态规划
东方雴翾18 分钟前
Dart语言的3D可视化
开发语言·后端·golang
雷渊21 分钟前
深入分析学习 Arthas 在项目中的应用
java·后端·面试