一、要素
- 必须有最终停止发展下线的边界条件,否则将无穷循环
- 必须有与原始问题结构一致的,但输入规模一定小于原始问题规模的递归结构
二、递归解决问题的步骤
step1. 不妨设该问题有解fnc(p),其中p为函数fnc的输入
step2. 递归
将原始问题p分解为k个子问题,,即p1, p2, p3, ... , pk
——由于求解原问题的函数为fnc, 因此求解各子问题的函数依然为fnc
——子问题对应的输入元素个数要小于原问题的输入元素个数
step3. 边界条件
建立子问题的解与原问题的解的关系
——根据解的关系得到递归结构
——子问题的最简形式存在解
下面用三个例子来说明递归算法求解问题的步骤:
例1——判断回文
步骤
step1. 不妨设已经有一个函数isPalindrome(s)可用来判断是否回文数,在这里我们可以设s='level'
step2. 将isPalindrome(s)进行分解:
isPalindrome('level') = isPalindrome('eve') and ('l' == 'l')
step3. 边界条件
len(s) <= 1 ——> True
代码实现
def isPalindrome(s): if len(s)<=1: return True else: return isPalindrome(s[1:-1]) and s[0]==s[-1] print(isPalindrome('levl'))
例2——全排列
步骤
step1. 不妨设已经有一个函数permutation(s)可用来解决该问题,假设s='ABC'
step2. 将原问题分解为规模更小的子问题:
字符‘A’ + permutation('BC')
字符‘B’ + permutation('AC')
字符‘C’ + permutation('AB')
s[i] + permutation(s(阴影))
step3. 边界条件
len(s) <= 1 ——> 输出其本身
代码实现
def permutation(s): if len(s) == 1: return s else: res = [] for i in range(len(s)): cha = s[i] rest = s[0:i]+s[i+1:] for j in permutation(rest): tar = s[i]+j res.append(tar) return res print(permutation('ABCd'))
扩展
值得一提的是,在Python中有一个模块可以帮助我们自动实现全排列功能——permutations
用法如下:
from itertools import permutations s = 'adc' print(permutations(s)) print(list(permutations(s)))
代码执行结果如下:
可以看到,用permutations模块得出的全排列是元组类型。
例3——汉诺塔问题
问题汉诺塔是一个发源于印度的益智游戏,也叫河内塔。相传它源于印度神话中的大梵天创造的三个金刚柱,一根柱子上叠着上下从小到大64个黄金圆盘。大梵天命令婆罗门将这些圆盘按从小到大的顺序移动到另一根柱子上,其中大圆盘不能放在小圆盘上面。当这64个圆盘移动完的时候,世界就将毁灭。
步骤
step1. 不妨设已经有一个函数hanio(num,start,end,helper)可用来解决该问题,其中num为圆盘数,start为起始圆柱,end为目标圆柱,helper为辅助圆柱
step2. 将原问题分解为规模更小的子问题:
step3. 边界条件
当num == 1时,直接移动即可:moveSingleDesk(source,target)
代码实现:
n = 3 source = ([3,2,1],'A') target = ([],'B') helper = ([],'C') def hanio(n,start,end,helper): if n == 1: moveSingleDisk(start,end) else: hanio(n-1,start,helper,end) moveSingleDisk(start,end) hanio(n-1,helper,end,start) def moveSingleDisk(start,end): x = start[0].pop() print('MOVING '+str(x)+' FROM '+start[1]+' TO '+end[1]) end[0].append(x) print(hanio(n,source,target,helper))