简单的递归讲解,小白也能听懂

🎉 前言

众所周知,递归是算法中很重要的一种思想,今天我希望以几个典例来讲讲我对递归的一些看法。废话不多说,让我们开始吧。

🎉 典例1 斐波那契数列

leetcode的第509题,是一道关于斐波那契数列的题目,题目如下:

斐波那契数列有这样的性质: f(n) = f(n-1) + f(n-2), 其中f(0) = 1,f(1) = 1。
现在给定一个正整数 n 要求计算出 f(n) 的大小

这道题目一般的解题思路是用循环的手段,不断的计算并累加,最终的到结果,参考代码如下:

class Solution {
    public int fib(int n) {
        if(n == 0){
            return 0;
        }
        int dp[] = new int[n];
        int res = 0;
        if(n == 1 || n==2){
            return 1;
        }
        dp[0] = 1;
        dp[1] = 1;
        for(int i=2;i<n;i++){
            dp[i] =  dp[i-1] + dp[i-2];
            if(i == n-1){
                return dp[i];
            }
        }
        return 0;
    }
}

这样看来代码一点也不简洁,但事实上如果你会一点递归的思想,用短短几行代码就能搞定。
先上代码:

class Solution {
    public int fib(int n) {
        if(n == 0){
            return 0;
        }
        if(n == 1 || n == 2){
            return 1;
        }
        return fib(n-1) + fib(n-2);
    }
}

代码很简单,我们可以逐行来分析一下
首先,我们需要明确fib(n)代表的是什么意思,显然,在代码中fib(n)表示斐波那契数列第n项,那么根据题意,我们可以将公式改写成

fib(n) = fib(n-1) + fib(n-2);

这样我们就得到了一个通项公式,任何一项斐波那契数列都可以用这个式子表示。
OK,再让我们回到源代码,我希望读者不要将fib(n)看成是一个函数,而是将其抽象成一个变量,
那么

if(n == 0){
		return 0;
	}
if(n == 1 || n == 2){
   		return 1;
   	}
   	return fib(n-1) + fib(n-2);

这几行代码就很好理解了,n=0表示第0项,根据题意返回0,n=1和n=2根据题意返回1,n>2,根据通项公式返回 第n-1和第n-2项之和,即fib(n-1) + fib(n-2),不知道讲到这里读者有没有get到我的点,如果没有请轻点喷😅。

这里还需要多说几句,其实前两个判断语句还起着终止递归的作用,因为本质上我们从实现细节的角度来看,最终递归是不可能一直进行下去的,fib(n-1)和fib(n-2)最终都会回到fib(1)+fib(2)上,所以这就是我为什么说判断语句起着终止递归的作用。

🎉 总结

从这道简单的例题中,我们可以总结出以下几点经验:
1.要明确递归函数的含义,必要时可将其抽象成一个变量
2.要有递归终止条件
3.要明确递归公式

最后附上几道练习,希望大家可以举一反三,触类旁通。

1.计算阶乘

//递归计算阶乘
class test01{
    public static void main(String[] args) {
        test01 t1 = new test01();
        System.out.println(t1.fib(5));
    }
    //fib表示前i项的阶乘
    public int fib(int n){
        if(n == 0 || n == 1){
            return 1;
        }
        return n*fib(n-1);
    }
}

这里的递归函数同样简洁,终止递归的条件语句 + 递推公式 n * fib(n-1),而这里fib(n-1)含义表示第n-1项的阶乘。

2.计算100以内的正整数之和

//递归计算100以内的正整数和
class test02{
    public static void main(String[] args) {
        test02 t2 = new test02();
        System.out.println(t2.fib(100));
    }
    //fib表示前i项的整数和
    public int fib(int n){
        if(n == 1){
            return 1;
        }
        return n+fib(n-1);
    }
}

3.计算10的n次方

//递归计算10的n次方
class test03{
    public static void main(String[] args) {
        test03 t3 = new test03();
        System.out.println(t3.fib(4));
    }
    //fib表示前i项的整数和
    public int fib(int n){
        if(n == 0){
            return 1;
        }
        return 10*fib(n-1);
    }
}
  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
递归树(Recursion Tree)是一种可视化递归算法的方式,它通过将递归算法转化为树形结构来帮助我们更好地理解递归算法的执行过程和时间复杂度。 在递归算法中,每次递归调用都会产生一个新的子问题,直到达到基本情况,然后逐级返回结果。这样的递归过程可以用一棵树来表示,其中每个节点代表一个递归调用,子节点代表对应的子问题,叶子节点代表基本情况的返回值。 举个例子,假设我们要求一个数组的所有子集,可以使用如下的递归算法: ``` void subsets(vector<int>& nums, int start, vector<int>& subset, vector<vector<int>>& res) { res.push_back(subset); for (int i = start; i < nums.size(); i++) { subset.push_back(nums[i]); subsets(nums, i+1, subset, res); subset.pop_back(); } } vector<vector<int>> subsets(vector<int>& nums) { vector<vector<int>> res; vector<int> subset; subsets(nums, 0, subset, res); return res; } ``` 我们可以将递归过程可视化为下面的递归树: ``` [] / | \ [1] [2] [3] / \ / \ | [1,2] [1,3] [2,3] [3,4] [1,2,3] / \ | [1,2,3] [1,3,4] [2,3,4] ``` 其中,[]代表一个子集,每个节点代表一次递归调用,左子节点代表将当前元素加入子集,右子节点代表不将当前元素加入子集。当递归到数组末尾时,就返回一个空子集。 通过递归树,我们可以更好地理解递归算法的执行过程,并且可以根据递归树来分析时间复杂度。在上面的例子中,递归树的深度为数组的长度N,每个节点会被访问一次,因此时间复杂度为O(2^N)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秋窗7

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值