1. 递归(分治)
最近刷到一些递归题目,总结了一下递归的程序编写框架。针对不同问题,递归函数有两种不同的形式:
- 递归累加问题:具有返回值的递归函数;
- 全排列问题:没有返回值,但对某一中间变量进行增删的递归函数。
对于递归问题,我一直有个有个很直观的概念,觉得递归树的同一层是同时执行的。实际上,是顺序执行,或者说,该递归树是以后根遍历的方式顺序执行的(因为一般的递归操作最后的返回值与左右子递归树相关,先递,后归,因此可以强行理解为,后根遍历)。
1.1 递归累加问题
对于第一种问题的递归函数一般只包含两部分内容:
- 返回的边界条件;
- 递归公式。
以斐波那契问题为例,我们可以很容得到斐波那契函数的递归函数:
def fib(x):
# 定义返回的边界条件
if x < 2:
return 0 if x == 0 else 1
# 定义递归公式
return fib(x - 1) + fib(x - 2)
print(fib(6)) # 打印结果为:8
1.2 第二种问题
这类问题通常可以通过在全排列中添加条件来减少全排列的计算次数,或者本身就是全排列问题。解决这类问题,我们的递归函数通常包含如下内容:
- 返回的边界条件(通常是将需要的数字全部排列好);
- 递归公式;
- 不断修改的全排列数组(先增加某一位,递归后减少该位置(可以设置访问标志位))。
比如全排列问题(给定一个没有重复数字的序列,返回其所有可能的全排列):
class Solution:
def permute(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
# 定义全排列数组和访问标志位
not_visit = [True for _ in range(len(nums))]
tmp = nums[:]
def dfs(position):
# 定义返回的边界条件
if position == len(nums):
res.append(tmp[:])
return
# 定义全排列访问
for index in range(0, len(nums)):
if not_visit[index]:
# 修改全排列数组和访问标志位(已访问)
tmp[position] = nums[index]
not_visit[index] = False
# 进入递归
dfs(position + 1)
# 修改全排列数组和访问标志位(该位置未访问)
not_visit[index] = True
res = []
dfs(0)
return res
比如N皇后问题(LeetCode 面试题 08.12. 八皇后):
import copy
class Solution:
def solveNQueens(self, n: int):
# 定义全排列数组
self.QueenLocation = []
# 全局变量,由递归边界条件返回结果
self.results = []
drawresults = []
# 开始递归
self.countQueen(n, 0)
for result in self.results:
drawresults.append(self.draw(result, n))
return drawresults
def countQueen(self, n, i):
# 定义递归边界条件
if i == n:
self.results.append(copy.copy(self.QueenLocation))
return
# 定义全排列访问
for j in range(n):
if not self.allisinline((i,j)):
# 修改(增加)全排列数组(同时也是标志位)
self.QueenLocation.append((i, j))
# 进入递归
self.countQueen(n, i+1)
# 修改(删除)全排列数组(同时也是标志位)
self.QueenLocation.remove((i, j))
# 确定该位置是否可以放置皇后
def allisinline(self, b):
for a in self.QueenLocation:
if self.isinline(a, b):
return True
return False
def isinline(self, a, b):
if a[1] == b[1] or a[0] == b[0]:
return True
elif (a[0] - b[0])/(a[1] - b[1]) == 1 or (a[0] - b[0])/(a[1] - b[1]) == -1:
return True
else:
return False
def draw(self,result, n):
temp = [['.' for i in range(n)] for i in range(n)]
for i, j in result:
temp[i][j] = 'Q'
temp = [''.join(line) for line in temp]
return temp
if __name__ == "__main__":
solu = Solution()
solu.solveNQueens(4)
2. 最大公因数
2.1 递归方法
def gcd(a: int, b: int):
if b == 0:
return a
else:
return gcd(b, a % b)
2.2 非递归方法
def NonRecursiveGcd(x,y):
while(y):
x , y = y , x % y
return x