母牛的故事——递归与循环两种解法比较与分析

题目

前几天看了一到需要用到递归函数的的题目如下
在这里插入图片描述
下面是输入输出样例
在这里插入图片描述

递归的解法

由于在题目中明确提到了 递归 二字,我首先的思路也是往递归这方面去靠。

下面就是构造其数学表达式

我们令F(n)表示第n年的母牛总数,则F(n)应该等于上一年母牛总数即F(n-1)加上上一年产出的牛数。显然上一年产出的牛数很难用函数F进行表示,又由于每一年产出的牛数等于其该年可进行生产的母牛数,因此我们考虑引进另外一个函数G(n)表示第n年可进行生产的母牛数
由上我们可以得到第一个表达式:

F(n) = F(n - 1) + G(n - 1)

然后我们考虑G(n)这个函数怎么构造。
根据题目中的信息,我们知道每头小牛从第四个年头开始进行生产。显然第n年可进行生产的母牛数应该等于n-1年可进行生产的母牛数加上该年刚好发育成熟,可进行生产的牛数
而新发育成熟的牛数刚好是两年前新生产下来的牛数即 F(n - 2) - F( n - 3)
因此我们得到关于G(n)的表达式:

G(n) = G(n - 1) + F(n - 2) - F(n - 3)

下面列出F(n)和G(n)的前几项数值作为递归的基底:

年份F(n)G(n)
111
221
331
442

然后我们就可以根据以上的思路写出 F(n) 和 G(n) 的代码:

int F(int n){
	if(n < 5){
		return n;
	}else{
		return F(n-1)+G(n-1);
	}
}
int G(int n){
	if(n < 4){
		return 1;
	}else{
		return G(n-1)+F(n-2)-F(n-3);
	}
}

然后关于实现题目中的输入输出要求,读者可自行实现。

存在的问题

我在第一次交代码的时候,判题系统显示超时
下面我们以求第7年牛的总数,分析其时间复杂度。

  1. 首先在 F(7) 中需要调用 G(6) 与 F(6)
  2. 在 F(6) 中需要调用 G(5)与 F(5) ;在 G(6) 中需要调用 G(5) 与 F(4) 与 F(3)
  3. 在调用过程中最后得到可直接返回的 F(n) (即满足n小于5的时候)与 G(n) (既满足n小于4的时候),依次返回
  4. 逐步返回函数值,最后得到 F(7) 的值

在这个例子中我们可以看到:每次调用F,又要再次调用两个函数,每次调用G,则要调用三个函数。
因此当n比较大时,完成运算的时间十分长。

另外一种解法——循环

循环解法的思路也是根据上面提到的两个表达式:

F(n) = F(n - 1) + G(n - 1)
G(n) = G(n - 1) + F(n - 2) - F(n - 3)

根据这两个表达式的递推关系,我们可以考虑分别构造数组:

int F[60] = {1,2,3,4,6};     //完成数组的构造以及前几项的赋值
int G[60] = {1,1,1,2,3};

由于题目已经规定输入n的范围是 0 < n < 55,在定义数组大小时比55稍大即可。然后就是用for循环依次对数组中的变量进行赋值:

	int i;
	for (i = 5; i < 60; i++) {
		F[i] = F[i - 1] + G[i - 1];
		G[i] = G[i - 1] + F[i - 2] - F[i - 3];
	}

然后即可得到第n年的牛数F[n - 1]。

小结

通过以上分析我们可以得知,用递归的方法解决问题的关键是找到其递推关系,其余的步骤都十分好下手。但当其输入的参数十分大时,由于函数的反复调用,极易造成时间过长,甚至出现 栈满 的情况。

而用循环的解法,虽然在题目没有给定参数范围的情况下数组的大小难以确定,但其有着线性的时间复杂度,运算快捷的优势,运行效率高于用递归函数的解法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值