算法和数据结构(Python)——动态规划

适用情况

求最值,有子序列相关

模式

  1. dp表法

思路

  1. 根据题目建立dp表,明确dp[i]的含义。
  2. 设置 base case ,初始化 dp 数组。
  3. 运用数学归纳法的思想,假设 dp[0…i-1] 都已知,想办法求出 dp[i]。动态找dp[i], dp[j]的变化关系,在什么条件下满足题目要求的变化。可以把初始化的值也考虑进来
    (但如果无法完成这一步,很可能就是 dp 数组的定义不够恰当,需要重新定义 dp 数组的含义;或者可能是 dp 数组存储的信息还不够,不足以推出下一步的答案,需要把 dp 数组扩大成二维数组甚至三维数组。)
def f(s1, s2):
	<1.创建dp表(初始化)>
    dp = [[0 for i in range(len(s2)+1)] for j in range(len(s1)+1)]

    <2.循环修改dp表>
    for i in range(1,len(s1)+1):     # 大循环表示列
        for j in range(1,len(s2)+1): # 小循环表示行
            <3.如果相等>
            if s1[i-1] == s2[j-1]:  
                dp[i][j] = 
            <4.如果不等>
            else:
                dp[i][j] = 最值()
    return dp[-1][-1]  
  1. 备忘录法 递归

思路

  1. 找原问题和子问题的变化量
  2. 根据题目确定函数的因变量
  3. 确定状态转移方程,子问题可以做出什么选择得到原问题
<1.定义备忘录>
memo = dict()

def f(n, arr):
	<2.查备忘录:避免重复>
	if n in	memo: return memo[n]
	
	<3.递归中止条件>
	if n ==	0: return 0
	if n < 0: return -1
	
	res = float('INF')
	for i in arr:
		<4.子问题无解>
		if f(n - i) == -1: continue
		
		<5.动态转移方程递归>
		res = min(res, 1 + f(n - i))
		
	<6.记入备忘录>
	memo[n] = res if res != float('INF') else -1
	return memo[n]

例题1 双字符二维dp表

leetcode 1143. (medium) 最长公共子序列
给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列。

一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
例如,“ace” 是 “abcde” 的子序列,但 “aec” 不是 “abcde” 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。

若这两个字符串没有公共子序列,则返回 0。

输入:text1 = “abcde”, text2 = “ace”
输出:3
解释:最长公共子序列是 “ace”,它的长度为 3。

解题思路:
创建dp表,注意dp表跟循环内ij的对应,大循环的索引i代表行,小循环的索引j代表列。
在这里插入图片描述

class Solution:
    def longestCommonSubsequence(self, text1: str, text2: str) -> int:
        # <1.创建dp表(初始化)> 注意dp表的对应关系
        dp = [[0 for i in range(len(text2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值