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

求阶乘

代码如下:

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))
相关推荐
阿童木写作38 分钟前
跨境电商图片翻译工具推荐:批量图片翻译+视频字幕翻译+智能抠图
python·macos·音视频·xcode
cui_ruicheng1 小时前
LangChain 应用开发(十四):Agent 上下文与记忆机制
服务器·人工智能·python·langchain
circuitsosk2 小时前
任务规划器的三种范式对比:ReAct、Plan-and-Execute 与 Tree-of-Thought 在真实业务中的取舍
前端·javascript·python·react.js·llm·ai agent
shehuiyuelaiyuehao2 小时前
算法31,前缀和,可被k整除的子数组
数据结构·python·算法
宸津-代码粉碎机2 小时前
AI攻防战升级!基于Spring AI构建Java应用自动免疫安全体系
java·大数据·开发语言·人工智能·python·安全·spring
测试19982 小时前
如何用appium搭建Android自动化测试框架?
自动化测试·软件测试·python·测试工具·职场和发展·appium·测试用例
程序员大雄学编程3 小时前
微积分46. 无穷级数四大核心性质:从理论到实践的全方位解析
python·学习·微积分·学习工具
数字化转型分享点滴3 小时前
## 工厂数字化管理系统的价值体现:构建制造全流程数据闭环
python
203号居民3 小时前
LeetCode hot 100 — 141. 环形链表2
算法·leetcode·链表
2301_800074214 小时前
map,list简单方法
windows·python·list