什么是递归
递归是指在一个函数或程序中调用自身的过程。递归函数通常通过在每次调用中传递不同的参数来处理问题。当函数或程序被调用时,它执行一些操作,然后可能会再次调用自身来执行相同的操作,直到达到某个特定的条件。这个过程可以看作是一种迭代,因为函数会多次重复执行相同的操作,但是在每次迭代中使用不同的参数。
递归通常用于处理那些具有自相似性质的问题,比如树形结构或者迭代式定义的数学函数。递归算法通常比迭代算法更简洁、易于理解和实现,但是也可能会在处理大型问题时导致栈溢出等性能问题。
递归-递和归
递:
一直往下面走,直到遇到推出条件。所以我们要有退出条件,不然一直向下走
而退出条件一般就是为某个参数时可以直接得到答案的时候
归:
说白了就是return到上一层的过程,注意每一层的参数是什么,它不是不变的,是通过你归给它的是什么,或者递在这一层时的参数是什么递归是指在一个函数或程序中调用自身的过程。递归函数通常通过在每次调用中传递不同的参数来处理问题。当函数或程序被调用时,它执行一些操作,然后可能会再次调用自身来执行相同的操作,直到达到某个特定的条件。这个过程可以看作是一种迭代,因为函数会多次重复执行相同的操作,但是在每次迭代中使用不同的参数。
不要只注意递,归非常重要
所以一个基本的递归程序要有下面的条件
- 有退出递的if判断
- 找到归的状态转移方程
小题引入-讲解
递的退出条件一般都是最小问题
状态转移方程两种看法:
有小问题去推大问题是怎么推的(正看)
大问题是怎么分解成为小问题的(反看)
递归算阶层
def back(n):
if n==1: # 递的退出条件
return 1
return n*back(n-1) # 状态转移方程
print(back(5))
退出条件:1的阶乘是1
- 状态转移:
- 正推,2的阶乘为 2*(2-1)!
- 反推,n的阶乘为 n*(n-1)!
- 通过这两种来观察
在给出一道类似的
斐波那契数列🍍
def back(n):
if n==2 or n==1:
return 1
if n<=0:
return 0
return back(n-1)+back(n-2)
退出条件:初始值
- 状态转移:
- 正推,3的斐波那契数列地方的值为 1+1=2!
- 反推,n的斐波那契数列地方的值为 (n-1)+(n-2)!
- 通过这两种来观察
来一道简单,并且经典的
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个m级的台阶总共有多少种跳法。
def back(n):
if n==1: # 退出条件
return 1
elif n==2: # 退出条件
return 2
else:
return back(n-1)+back(n-2) # 状态转移
练习递归
会了前面几道题,只能说明你初步的了解递归算法了
然后就是真正的递归题:
回溯算法
DFS
知道最小时怎么解决是重点
得到组合和排列
不要使用Python库写出组合库
# 元素列表
element = [i for i in range(4)]
下面是使用库的
# 组合
print(list(itertools.combinations(element, 2)))
# 排列
print(list(itertools.permutations(element, 2)))
# 不使用库
# 组合
def term(element, n):
"""
:param element: 元素列表
:param n: 取几个元素进行组合
:return: 返回组合列表
"""
if n > len(element): # 取的数大于元素列表总数,返回[]
return []
elif n == len(element): # 取的数等于元素列表长度,返回元素列表
return [element]
elif n == 1: # 当取的数为1的时候,就是将元素列表里的数单独取出来
return [[i] for i in element]
else:
res = [] # 定义单前层的组合
for i in range(len(element) - n + 1): # 头元素可取值,超出这个范围就不能选n个数了
for c in term(element[i + 1:], n - 1): # 尾元素的可取值
res.append([element[i]] + c) # 当前的element[i]是什么?
return res # 又回返回给 for c in rec 会变成这个样子的,重点!!!!
# 排列
def pai(element, n):
"""
:param element: 元素列表
:param n: 选取元素个数
:return: 返回全排列列表
"""
result = [] # 结果集
def helper(arr, candidates): # arr是当前的排列,初始为空,candiates是当前元素列表
if len(arr) == n: # 当前排列长度到达目标退出
result.append(arr)
else:
for i in range(len(candidates)): # 每一个位置都放,除了已经选过的值,每一次循环都是这个位置放的元素
helper(arr + [candidates[i]], candidates[:i] + candidates[i + 1:])
helper([], element)
return result
迷宫寻路
题:随机生成迷宫,自己定义起点和终点,找出一条可行路径
import random
# 随机生成迷宫
print("迷宫大小,输入后随机生成迷宫")
s = list(map(int, input().split()))
c, h = s[0], s[1]
mie = [[random.choice([0, 0, 0, 1]) for _ in range(h)] for _ in range(c)]
for i in mie:
print(i, ",")
print("输入起点和终点,以左上角为原点,下是x,右是y")
l_q_z = [list(map(int, input().split())) for _ in range(2)]
q_x, q_y, z_x, z_y = l_q_z[0][0], l_q_z[0][1], l_q_z[1][0], l_q_z[1][1]
# DFS寻路函数
def find(x, y, x1, y1, list_M):
"""
迷宫参数
:param x: 起始点
:param y: 起始点
:param x1: 终点
:param y1: 终点
:param list_M: 迷宫
:return: 路线列表
"""
move = ((1, 0), (-1, 0), (0, 1), (0, -1))
def dfs(x, y, path):
if x == x1 and y == y1:
return path + [(x, y)]
list_M[x][y] = 1
for x_m, y_m in move:
nx, ny = x + x_m, y + y_m
if 0 <= nx < len(list_M) and 0 <= ny < len(list_M[0]) and list_M[nx][ny] == 0:
ret = dfs(nx, ny, path + [(x, y)])
if ret is not None:
return ret
return None
# 调用深度优先搜索函数
res = dfs(x, y, [])
# 返回结果
return res
# 尝试
print(find(q_x, q_y, z_x, z_y, mie))
# 该迷宫只能找到一条就会退出,而且不是最优路径
找出所有路径
def find(x, y, x1, y1, list_M):
"""
迷宫参数
:param x: 起始点
:param y: 起始点
:param x1: 终点
:param y1: 终点
:param list_M: 迷宫
:return: 路线列表
"""
move = ((1, 0), (-1, 0), (0, 1), (0, -1))
L = [] # 放入所有可行路径
def dfs(x, y, path):
if x == x1 and y == y1:
return L.append(path + [(x, y)])
list_M[x][y] = 1
for x_m, y_m in move:
nx, ny = x + x_m, y + y_m
if 0 <= nx < len(list_M) and 0 <= ny < len(list_M[0]) and list_M[nx][ny] == 0:
dfs(nx, ny, path + [(x, y)]) # 一直运行,直到到终点退出
list_M[nx][ny] = 0 # 关键:回到上一级时,将当前的点转为未走过
return None
# 调用深度优先搜索函数
dfs(x, y, [])
# 返回结果
return L
找出最优呢?