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

求阶乘

代码如下:

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))
相关推荐
荆棘鸟智能4 分钟前
虫情测报灯图像识别算法实践:小目标检测、粘连计数与飞虱细粒度分类
算法·目标检测·分类
逸A15 分钟前
携程app逆向那些事(ai agent能力偏弱时)
人工智能·python·安全
silvamux_25 分钟前
OpenAI Python SDK v1 迁移实战
开发语言·python
爱读书的小胖26 分钟前
LeetCode 27. 移除元素(C)解题分析
数据结构·算法
旋生万物26 分钟前
螺旋数不是玄学:Python 实现广义复数与等角螺线
开发语言·人工智能·python·云原生·aigc·软件工程·后端开发
科技小E27 分钟前
敏感数据不敢上云训练?本地大模型推理服务器DLTM私有化部署,让训练全程留在企业内网
大数据·算法·自动化
小小程序猴137 分钟前
用工程视角建模企业AI培训周期:三段账本估算器(Python实现)
开发语言·人工智能·python
小草cys1 小时前
用 GPT 直接生成可编辑 PPTX 的实操记录,artifact-tool是OpenAICodex环境专用
gpt·算法·pptx
爱读书的小胖1 小时前
Codewars: A Brave New Wordle(C)解题分析
c语言·数据结构·算法
十二同学啊1 小时前
Python FastAPI 项目使用 Docker 部署并映射端口(完整教程)
python·docker·fastapi