递归与动态规划实战代码解析

求阶乘

代码如下:

python 复制代码
import sys
sys.setrecursionlimit(10**6)
dic = {0:1}
def f(n):
    if n in dic.keys():
        return dic[n]
    else: 
        dic[n] = n * f(n - 1)
    return dic[n] % 998244353
n = int(input())
print(f(n))

错误示例:

RTE


RTE


MLE


TLE

斐波那契数列Ⅰ

代码如下:

python 复制代码
#法一:
def f(n):
    if n == 1 or n == 2:
        return 1
    else:
        return f(n - 1) + f(n - 2)
n = int(input())
print(f(n))
python 复制代码
法二:
dic = {1: 1, 2: 1}
def f(n):
    if n in dic.keys():
        return dic[n]
    else:
        dic[n] = f(n - 1) + f(n - 2)
    return dic[n]
n = int(input())
print(f(n))

分形

代码如下:

python 复制代码
def B(n):
    if n == 1:
        return ['X']
    pre = B(n - 1)
    size = len(pre)
    # 上半部分:B(n-1) + 空格 + B(n-1)
    top = [a + ' ' *  size + b for a, b in zip(pre, pre)]
    # 中间部分:空格 + B(n-1) + 空格
    mid = [' ' * size + a + ' ' * size for a in pre]
    # 下半部分:B(n-1) + 空格 + B(n-1)
    bottom = [a + ' ' *  size + b for a, b in zip(pre, pre)]
    return top + mid + bottom

def main():
    while True:
        try:
            n = int(input())
            if n == -1:
                break
            ans = B(n)
            for row in ans:
                print(row)
            print('-')
        except EOFError:
            break
if __name__ == '__main__':
    main()
  1. 为什么不能直接 top = [pre + ' ' * size + pre]

· pre 是一个列表,例如当 n=2 时, pre 是 ['x x', ' x', 'x x'] 。

· 列表和字符串不能直接用 + 号拼接,Python 会报错: TypeError: can only concatenate list (not "str") to list 。

· 即使想把列表当成字符串处理,也会得到错误的结构,因为我们需要的是逐行拼接,而不是把整个列表当成一个整体。

  1. 为什么要用 zip(prev, prev)

· zip(prev, prev) 的作用是把 prev 列表中的每一行,和它自己配对成元组

例如 prev = ['a', 'b', 'c'] , zip(prev, prev) 会得到 [('a', 'a'), ('b', 'b'), ('c', 'c')] 。

· 然后用列表推导式 [a + ' ' * size + b for a, b in zip(prev, prev)] ,就可以把每一行 a 和 b (其实是同一行)用空格拼接起来,得到新的一行。

  1. 举个具体例子(n=2)

· n=1 时, prev = ['x'] , size = 1 。

· top = [a + ' ' * 1 + b for a, b in zip(prev, prev)] → ['x x'] 。

· mid = [' ' * 1 + line + ' ' * 1 for line in prev] → [' x '] 。

· bottom = ['x x'] 。

汉诺塔问题

代码如下:

python 复制代码
def hanoi(n, start, midpoint, target):
    if n == 1:
        print(f"Move disk 1 from {start} to {target}")
        return
    # 将 n-1 个盘子从 start 借助 target 移动到 midpoint
    hanoi(n -1, start, target, midpoint)
    # 移动第 n 个盘子
    print(f"Move disk {n} from {start} to {target}")
    # 将 n-1 个盘子从 midpoint 借助 start 移动到 target
    hanoi(n - 1, midpoint, start, target)
n = int(input())
# 调用函数,A 是起始柱,C 是目标柱,B 是辅助柱
hanoi(n, 'A', 'B', 'C')

斐波那契数列Ⅱ

代码如下:

python 复制代码
def pre_fib(max_n):
    fib = [0] * (max_n + 1)
    fib[1] = fib[2] = 1
    for i in range(3, max_n + 1):
        fib[i] = (fib[i - 1] + fib[i - 2]) % 998244353
    return fib
max_n = 10000
fib = pre_fib(max_n)
t = int(input())
for i in range(t):
    n = int(input())
    print(fib[n])

优势:

  1. 一次计算,多次使用 - 适合处理多个测试用例

  2. 没有递归深度问题

  3. 时间复杂度 O(MAX_N),查询时间复杂度 O(1)

  4. 内存友好 - 只需要一个列表存储结果

错误示例:

python 复制代码
from functools import lru_cache
@lru_cache(maxsize=None)
def f(n):
    if n == 1 or n == 2:
        return 1
    return (f(n - 1) + f(n - 2)) % 998244353
t = int(input())
for i in range(t):
    n = int(input())
    print(f(n))

python 复制代码
dic = {1:1, 2:1}
def f(n):
    if n in dic.keys():
        return dic[n]
    dic[n] = f(n - 1) + f(n - 2)
    return dic[n]
t = int(input())
for _ in range(t):
    n = int(input())
    print(f(n) % 998244353)

python 复制代码
dic = {1:1, 2:1}
def f(n):
    if n in dic.keys():
        return dic[n]
    dic[n] = f(n - 1) + f(n - 2)
    return dic[n] % 998244353
t = int(input())
for _ in range(t):
    n = int(input())
    print(f(n))

python 复制代码
def f(n):
    if n == 1 or n == 2:
        return 1
    return (f(n - 1) + f(n - 2)) % 998244353
t = int(input())
for i in range(t):
    n = int(input())
    print(f(n))

滑雪

代码如下:

python 复制代码
import sys
sys.setrecursionlimit(10**6)
R, C = map(int, input().split())
mapp = []
for i in range(R):
    mapp.append(list(map(int, input().split())))
# 记忆化数组,dp[i][j] 表示从 (i,j) 出发的最长滑坡长度
dp = [[-1] * C for _ in range(R)]

def dfs(x, y):
    if dp[x][y] != -1:
        return dp[x][y] #记忆化,避免重复计算
    max_len = 1#自己本身算一个长度
    dic = [(0, -1), (0, 1), (-1, 0), (1, 0)]
    for i in range(4):
        xx, yy = x + dic[i][0], y + dic[i][1]
        if xx < 0 or xx >= R or yy < 0 or yy >= C:
            continue
        if mapp[xx][yy] < mapp[x][y]:
            max_len = max(max_len, dfs(xx, yy) + 1)
    dp[x][y] = max_len
    return max_len #返回结果,给上一层调用者

# 计算所有点的dp值
for i in range(R):
    for j in range(C):
        dfs(i, j)
# 直接找dp表中的最大值
ans = 0
for i in range(R):
    for j in range(C):
        ans = max(ans, dp[i][j])
print(ans)

01背包

代码如下:

python 复制代码
n, V = map(int, input().split())
dp = [0] * (V + 1)
for i in range(1, n + 1):
    vi, wi = map(int, input().split())
    for j in range(V, vi - 1, -1):
        dp[j] = max(dp[j], dp[j - vi] + wi)
print(dp[V])

爬楼梯

代码如下:

递归法

python 复制代码
from functools import lru_cache
@lru_cache(maxsize=None)
def dfs(n):
    if n == 1:
        return 1
    elif n == 2:
        return 2
    return dfs(n - 1) + dfs(n - 2)
n = int(input())
print(dfs(n))

动态规划:

python 复制代码
def climb_stairs(n):
    if n == 1:
        return 1
    if n == 2:
        return 2 
    dp = [0] * (n + 1)
    dp[1] = 1
    dp[2] = 2 
    for i in range(3, n + 1):
        dp[i] = dp[i - 1] + dp[i - 2]
    return dp[n]

n = int(input())
print(climb_stairs(n))
相关推荐
CLX05051 小时前
Golang如何做图片处理缩放_Golang图片处理教程【收藏】
jvm·数据库·python
2301_812539671 小时前
mysql如何限制用户连接数_使用MAX_USER_CONNECTIONS优化并发
jvm·数据库·python
X56612 小时前
Python Django怎么处理404_关闭DEBUG模式并自定义配置全局404与500友好错误重定向页面
jvm·数据库·python
m0_748554812 小时前
golang如何集成Etcd配置中心_golang Etcd配置中心集成方法
jvm·数据库·python
橘白3162 小时前
rl笔记(一):策略梯度更新算法推导
人工智能·算法·机器人·强化学习
hhhhhaaa2 小时前
多节点矩阵式任务系统:统一配置中心与动态规则引擎架构设计
后端·算法·架构
hnxaoli2 小时前
win10小程序(二十一)凭证汇总重复值抽取
python
qwert10372 小时前
深入解析Python标识符:定义、规则、规范与实践指南
开发语言·数据库·python
Jetev2 小时前
Golang怎么做API网关_Golang API网关教程【总结】
jvm·数据库·python