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

求阶乘

代码如下:

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))
相关推荐
练习时长一年1 小时前
LeetCode热题100(二叉树的最大路径和)
算法·leetcode·职场和发展
不知名的老吴1 小时前
Lambda表达式与新的Streams API相结合
开发语言·python
2401_872418787 小时前
算法入门:数据结构-堆
数据结构·算法
weelinking8 小时前
【产品】12_接入数据库——让数据永久保存
jvm·数据库·python·react.js·数据挖掘·前端框架·产品经理
程序大视界8 小时前
【Python系列课程】Python正则表达式(下):环视、命名分组与日志实战
开发语言·python·正则表达式
xwz小王子9 小时前
手术机器人登上Science Robotics:2毫米纤细手臂,从3厘米切口完成腰椎神经减压
算法·机器人
TickDB9 小时前
美股行情 API 接入避坑:REST 快照、WebSocket 推送、盘前盘后数据的边界
人工智能·python·websocket·行情数据 api
枫叶v.9 小时前
Agent 分层存储架构设计:从记忆方法到中间件选型
开发语言·python
水兵没月9 小时前
逆向实战小记——某ToB商城网站分析学习
python·网络爬虫
黎阳之光9 小时前
视频孪生智护供水生命线:黎阳之光赋能医疗与园区水务高质量升级
运维·物联网·算法·安全·数字孪生