从零开始的递归生活(一)

递归一直就是老大难的问题,可每一个学编程的人都绕不开它,下面我就通过一系列案例来教大家学习一下怎么使用递归这种思想。

 光说原理太没意思,我们通过一个问题来看看递归的原理,打印1到100的和,这个问题太简单了,一个循环不就搞定了嘛,比如这样

int ADD()
{
	int ans=0;
	for(int i=1;i<=100;i++)
		ans+=i;
	return ans;
}

我们看看递归怎么解决,先想一个递归公式。我们需要将规模减少,可见如果要实现这个效果我们需要引入参数。我们定义一个n,让每一次递归引用ADD2都让n-1,我们return ADD2(n-1)这样规模就变小了,不过我们要的最终结果是和,所以这个时候还需要加上当前的数字n,那么我们可以得出递归公式是return n+ADD2(n-1)。还少一点点东西,我们不能无限制的减小啊,所以给一个出口,题目要求是要1到100的和,所以我们的出口条件是n等于1时,返回 1。下面我们把程序写出来

int ADD2(int n)
{
	if(n==1)
		return 1;
	return n+ADD2(n-1);
}

一个简单的递归就完成了。这个似乎太简单了,我们下面来一个稍微复杂一点的。

给定一个数组,使用递归求数组的任意连续位置的和

这个题目有种换汤不换药的既视感,现在我们做这个题目是不是感觉呼之欲出了,但是就是可能就是写不出来,且看下面的操作,上一个题目我们在ADD2这个函数中增加了n作为传递的参数,这个题目我们需要知道求和的数组的开始和结尾,所以我们引入更多的参数,ADD3(int start,int end)。由于需要使用主函数中的数组,所以在数组中引入ADD3(int a[],int start,int end)。现在考虑一下递归公式是什么,看下面这个图

我们把整个数组分割一下,把第一个部分分割出来,然后我们发现每一次都可以分割出来一个新的小块,那么我们尝试写一个递归公式

a[begin]+ADD3(a,begin+1,end),此时终点不用变化,起点被我们移动到下一个位置了,问题就被我们分解了。下面来看看出口是什么,因为我们是从开始start的位置一直加到end为止,由于我们让start不断增加,所以出口就很简单了。if(begin==n-1)我们这个时候应该返回什么呢,最后一个位置的start就行,return a[start]。这个函数就写好了,代码在下面了。 

int ADD3(int a[],int begin,int end)
{
	if(begin==end-1) return a[begin];
	return a[begin]+ADD3(a,begin+1,end);
}

这个时候是不是有点感觉了。不急,来我们再看一个题目:给定两个字符串用递归的方法判断两个字符串是否相等

这次是判断两个字符串是否相同,所以我们返回bool型,由于是要比较两个字符串,所以参数就是两个字符串bool f(string s1,string s2),下面慢慢考虑如何判断字符串相同。这个题目我们一拿到手就能想到,如果两个字符串的长度不相等那么它们一定不相等

那么if(s1.length()!=s2.length) 那么return false;然后怎么做呢,还记得上面我们把数组分割出来一小块吗,这里我们来画一个图

我们把字符串对齐,从第一个位置切一刀,我们比较一下第一个位置的字符是否相同,然后我们截取红线右边的大块字符,然后每一次都对第一个位置切一刀进行判断,如图

我们发现问题基本上被我们解决了,(注:这里我用的是c/c++所以我们用substr求子串,substr(1)表示截取第二个位置到串的结尾。)我们来整理一下代码 

bool f(string s1,string s2)
{
	if(s1.length()!=s2.length())	 return false;
	if(s1[0]!=s2[0]) return false;
	return f(s1.substr(1),s2.substr(1));
} 

似乎我们已经完成了,不过为了严谨,我们还需要考虑一下空字符串。如果两个字符串都为空那么返回true,我们可以写成if(s1.length()==0&&s2.length()==0)  return true;

bool f(string s1,string s2)
{
	if(s1.length()!=s2.length())	 return false;
	if(s1.length()==0&&s2.length()==0)  return true;
	if(s1[0]!=s2[0]) return false;
	return f(s1.substr(1),s2.substr(1));
} 

 我们这个代码还能改进一下,由于我们最先判断两个字符串个数不相同就返回false,所以我们只需要判断s1为空返回true即可

bool f(string s1,string s2)
{
	if(s1.length()!=s2.length())	 return false;
	if(s1.length()==0)  return true;
	if(s1[0]!=s2[0]) return false;
	return f(s1.substr(1),s2.substr(1));
} 

现在我们就把这个题目完成了。

让我们回顾一下我们这三个题目解法的共通之处:先是确定返回的类型,是整型还是布尔型等等。然后我们找递归公式,这一步最为关键,我们时常需要在这一步考虑参数,如果难以递归就适当添加参数,我们找到递归公式之.最后再给递归程序寻找递归出口。

可以把常见的简单的问题改成递归问题,尝试解决,找一找递归的感觉,之后下一篇会更新递归的经典问题。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值