算法——(2)动态规划
一. 解题思路
1. 暴力解决——递归
2. 记忆搜索——不关心计算的顺序O(N*aim2)
建立一个map:将需要递归的参数当作key,将结果当作value
3. 动态规划——规定计算的顺序。本质是使用额外的空间记录每一暴力搜索的结果——O(N*aim2)—>O(N*aim)
1. 建立一个矩阵dp
2. 按照计算顺序(一般从左到右,从上到下),记录每一次计算的结果
二、常见题目:
1. 若有货币的种类记在arr数组中,每种货币可以有任意张,给定aim总价值,求有多少种组合方法。
1)建立矩阵:dp[i][j]:代表货币为:arr[0...i]组成j的组合可能
0 | 1 | 2 | ... | j - 1 | j | ... | aim | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
... | ||||||||
i -1 | dp[i-1][j] | |||||||
i | dp[i][j-1] | dp[i][j] | ||||||
... | ||||||||
N-1 |
初始化矩阵:
2)分析:dp[i][j] =
- dp[i-1][j] 不使用arr[i]
- dp[i-1][j-arr[i]] 只用一张arr[i]
- dp[i-1][j-2*arr[i]] 使用两张arr[i]
- ....
总结:dp[i][j] = dp[i-1][j] + dp[i-1][j -arr[i]] + dp[i-1][j-2*arr[i]] +...
=dp[i][j-arr[i]] + dp[i-1][j] ——O(N*aim)
2. 给定一个矩阵,从左上角开始,每次只能向右或者下走,最后到达右下角,路径上所有的数字和称为路径和。返回所有路径和中的最小值
给定矩阵m:M*N,例如:
1 | 3 | 5 | 9 |
8 | 1 | 3 | 4 |
5 | 0 | 6 | 1 |
8 | 8 | 4 | 0 |
1)设定矩阵dp:M*N,dp[i][j]代表,到达(i,j)的最小路径和
1 | 4 | 9 | 18 |
9 | |||
14 | |||
22 |
2)分析dp[i][j]:
1. 初始化:dp[i][0] = dp[i-1][0] + m[i][0]
dp[0][j] = m[0][j] + dp[0][j-1]
2. 对于dp[i][j] = min{dp[i-1][j],dp[i][j-1]}
3. 返回数组arr的最长递增子序列的长度。——LIS
例如:arr=[2, 1, 5, 3 ,6, 4, 8, 9, 7]
dp = [1, 1, 2, 2, 3, 3, 4, 5, 1],最后输出5
1)设一个dp[i],代表arr[0...i]的最长递增子序列长度
2)dp[i] = max{dp[j] = 1, 0<=j <=i and arr[j] < arr[i]},如果不满足,则为1
4. 求str1和str2的最长公共子序列——LCS
另:求str中的最长回文——str 和 str.reverse的LCS问题
str1:M, str2:N,建立M*N 的矩阵dp,其中dp[i][j]代表str1[0....i]和str2[0...j]的最长公共子序列
1)初始化
- 对dp[i][0],若str1[i] == str2[0],则dp[i~M][0]=1
- 对dp[0][j],如果str2[j] == str1[0],则dp[0][j~N]=1
0 | 1 | 2 | ... | j - 1 | j | ... | aim | |
0 | ||||||||
1 | ||||||||
2 | ||||||||
... | ||||||||
i -1 | dp[i-1][j-1] | dp[i-1][j] | ||||||
i | dp[i][j-1] | dp[i][j] | ||||||
... | ||||||||
N-1 |
2)比较dp[i-1][j-1]、dp[i-1][j-1]、dp[i-1][j-1],得到最长的。再次基础上根据元素是否相同,确定是否+1
5. 0/1背包问题。一个背包中W,有N件物品,每件都有自己的价值,记在数组v中,也有自己的重量,记在数组w中。每个问题只能放或者不放,要求在不超重的情况下,求最大价值。
1)创建矩阵dp[i][j],代表前i件物品,不超过重量j的最大价值
2)分析dp[i][j]:
- 不拿物品i:总价值:dp[i -1][y]
- 拿物品i:总价值:dp[i][y-w[i]] + v[i]
取这两个的最大值。则最终dp最右下角的值就是结果。
6. 给定str1,str2,ic,dc,rc分别代表插入、删除、替换一个字符的代价。求str1——>str2的最小代价
1)设str1、str2长度分别为M、N,创建一个M*N的矩阵,其中dp[i][j]代表:str[0~i-1]——>str2[0~j-1]的最小代价
2)初始化:
- dp[0][0] = 0
- dp[i][0] = dc
- dp[0][j] = ic
3)dp[i][j]四种情况:
- dc + dp[i-1][j]
- ic + dp[i][j-1]
- dp[i-1][j-1]
- dp[i-1][j-1]+rc