递归思想与汉诺塔问题
概念
这两天在复习Python基础,因为蛮久没写过正紧的代码了,今天学习到了递归这里,发现了自己上学期面试中兴测试那会遇到的一个问题,反转一个字符串。记得当时就是直着想,写了一大段的代码,最终实现没实现,我都不确定。现在突然感觉羞愧难耐,我的代码水平的确退步了很多。我还记得大学前两年是写过这样的问题的。
最好的方法就是使用程序递归。递归就是函数在代码里面调用了自身,从而实现了一个递归链条。递归的思想和数学上的数学归纳法很相似。数学归纳法说的是先证明n取N 0时命题成立,后假设n=N k也满足命题,证明n=N k+1也满足命题,就可以证明命题成立。
递归包含两个部分,一个是基值,也就是N 0。还有一个就是链条关系。实现方面我们就需要一个基质和分支语句实现。
阶乘计算
例如我们要计算N的阶乘,可以使用下面的代码。
def cal(n):
if n = 0:
return 1
else:
return n*cal(n-1)
我的感觉是如果我们需要求解的问题可以分化成一个二元问题的递归就可以使用递归来写代码。比如阶乘中,任何一个数的阶乘都等于它本身×后一个数字的阶乘,且这个关系一直存在,直到基值为止。
反转字符串
说到这里递归的概念我们大概有了了解,再回到开头我之前遇到的反转字符串的问题,分析它该如何解决。我们需要把第一位字符放到最后,然后,第二个字符放在倒数第二的位置,依次往后。放第一个字符的时候,就是一个二元问题,剩下的为一元,第一个字符为一元。剩下的字符单独看成一个需要反转。下一层就是在这个小团里面在把第一个放在最后。基值为当字符为空的时候,它的反转就是它本身。所以代码如下。
def vars(s):
if s == "":
return s
else:
return vars(s[1:])+s[0]
print(vars("abcd"))
通过上述语句可以实现字符串的反转。第一个字母和后面的调换,后面的字母也这样,往复递归,使得字符串反转。abcd - bcda - cdba - dcba
汉诺塔问题
汉诺塔问题是一个很有趣的问题。说的是,有三个柱子,A柱上有金字塔形状的圆饼从上到下堆在一起,一共有n个圆饼,现在需要将A柱上的所有圆饼移动至C柱,中间还有一个空的B柱。要求移动的过程中,不能出现小圆饼在大圆饼下面的情况。问要怎么移动,同时需要移动多少次?
这个问题让我们人来计算可能会很麻烦,且随着n的增大,难度会显著提升。这时候我们就要分析问题了。如果只有一个圆饼,我们可以直接将圆饼拿到C柱。当有两个圆饼的时候,我们无疑是要将小的移动至B柱,然后大的移动至C柱,然后小的在跟上去C柱。
所以我们可以尝试去编写程序来实现这个功能。
count = 0 #标记移动的次数
def hnt(n, src, dst, mid):
global count
if n == 1:
print("{}从{}到{}".format(n, src, dst))
count += 1
else:
hnt(n-1, src, mid, dst) #将n-1个搬到中间
print("{}从{}到{}".format(n, src, dst)) #把编号n搬到右边
count += 1
hnt(n-1, mid, dst, src) #将中间n-1个搬到右边
hnt(3, 'a', 'c', 'b')
print(count)
1从a到c
2从a到b
1从c到b
3从a到c
1从b到a
2从b到c
1从a到c
7
以上是结果。简单就完成了,蛮厉害的,主要还是会分析,思考要用递归。汉诺塔代码中else部分的count的加可以好好思考思考为什么。