-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
cbfe88d
commit 760335d
Showing
1 changed file
with
160 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
## 常见的 DP 问题思路 | ||
|
||
1.三角形找一条从顶到底的最小路径 | ||
|
||
``` | ||
设状态为 f(i,j), 表示从从位置 (i,j) 出发, 路径的最小和, 则状态转移方程为: | ||
f(i,j) = min{ f(i+1,j), f(i+1,j+1) } + (i,j) | ||
/\ | ||
/\/\ | ||
/\/\/\ | ||
/\/\/\/\ | ||
``` | ||
|
||
2.最大子数组和 | ||
|
||
``` | ||
设状态为 f[j], 表示以 a[j] 结尾的最大连续子序列和, 状态转移方程如下: | ||
f[i]= max(f[i-1]+a[i], a[i]); // 对于数组里的一个整数, 它只有两种选择: 1,加入之前的SubArray; | ||
2.自己另起一个 SubArray. | ||
maxsum = max(maxsum,f[i]); // 数组当中最大的 | ||
``` | ||
|
||
3. 回文最小划分次数 | ||
|
||
``` | ||
对输入的字符串划分为一组回文字符串, 最小的分割次数 | ||
所以要转换成一维 DP. 如果每次, 从 i 往右扫描, 每找到一个回文就算一次 DP 的话, 就可以 | ||
转换为 f(i)= 表示子串 (0, i) 的最小回文切割, 则状态转移方程为 | ||
a) 当字串 s.substring(0,i+1) (包括i位置的字符)是回文时, dp[i] = 0(表示不需要分割); 否则, | ||
dp[i] = i (表示至多分割i次); | ||
b) 对于任意大于1的i, 如果 s.substring(j,i+1) ( 1 <= j <= i, 即遍历i之前的每个子串)是回文时 | ||
dp[i] = min(dp[i], dp[j-1]+1); | ||
``` | ||
|
||
|
||
4.最佳时间买卖股票 | ||
|
||
``` | ||
设状态f(i)表示区间[0,i-1]上的最大利润,设置状态g(i), 表示区间[i,n-1]上最大利润. | ||
则最大利润为max{f(i)+g(i)};允许在一天内买进又卖出, 相当于不交易, 因为题目的规定是最多两次, 而不是一定要两次 | ||
``` | ||
|
||
|
||
5. 判断字符串s3是否由s1,s2交叉存取组成 | ||
|
||
``` | ||
设状态 f[i][j], 表示 s1[0:i] 和 s2[0:j], 匹配 s3[0:i+j]. | ||
如果 s1 的最后一个字符等于 s3 的最后一个字符, 则 | ||
f[i][j]=f[i-1][j]; | ||
如果 s2 的最后一个字符等于 s3 的最后一个字符, 则 | ||
f[i][j]=f[i][j-1]. | ||
因此状态转移方程如下: | ||
f[i][j] = ( | ||
s1[i - 1] == s3 [i + j - 1] && f[i - 1][j]) || | ||
s2[j - 1] == s3 [i + j - 1] && f[i][j - 1] | ||
); | ||
``` | ||
|
||
|
||
6.给定一个矩形表格, 求从顶到底的最小和 | ||
|
||
``` | ||
Minimum Path Sum | ||
设状态为 f[i][j], 表示从起点 (0; 0) 到达 (i; j ) 的最小路径和, 则状态转移方程为: | ||
f[i][j]=min(f[i-1][j], f[i][j-1])+grid[i][j] | ||
``` | ||
|
||
|
||
7.使两个字符串相等, 最小的编辑次数 | ||
|
||
``` | ||
Edit Distance | ||
设状态为 f[i][j], 表示 A[0:i] 和 B[0:j] 之间的最小编辑距离. | ||
设 A[0:i] 的形式是 str1c, B[0:j] 的形式是 str2d, | ||
1. 如果 c == d, 则 f[i][j] = f[i-1][j-1]; | ||
2. 如果 c != d, | ||
(a) 如果将 c 替换成 d, 则 f[i][j] = f[i-1][j-1]+1; | ||
(b) 如果在 c 后面添加一个 d, 则 f[i][j] = f[i][j-1]+1; | ||
(c) 如果将 c 删除, 则 f[i][j] = f[i-1][j]+1; | ||
``` | ||
|
||
|
||
8.给定一串数字, 1对应A, 2对应B,26对应Z, 求有多少种解码方式 | ||
|
||
``` | ||
Decode Ways | ||
和爬楼梯问题一样, | ||
设 f (n) 表示爬 n 阶楼梯的不同方法数, 为了爬到第 n 阶楼梯, 有两个选择: | ||
1) 从第 n-1 阶前进 1 步; | ||
2) 从第 n-2 阶前进 2 步; 需要进行边界判断(<=26) | ||
因此, 有 f (n) = f (n-1) + f (n-2). 这是一个斐波那契数列. | ||
``` | ||
|
||
|
||
9. 不同的子序列 Distinct Subsequences | ||
|
||
``` | ||
给定2个字符串a, b, 求b在a中出现的次数. 要求可以是不连续的, 但是b在a中的顺序必须和b以前的一致. | ||
Here is an example: S = "rabbbit", T = "rabbit" | ||
Return 3. | ||
类似于数字分解的题目. dp[i][j]表示:b的前j个字符在a的前i个字符中出现的次数. | ||
如果S[i]==T[j], 那么dp[i][j] = dp[i-1][j-1] + dp[i-1][j]. | ||
意思是:如果当前S[i]==T[j], 那么当前这个字母即可以保留也可以抛弃, 所以变换方法等于保留这个字母的变换方法加上不用这个字母的变换方法. | ||
如果S[i]!=T[i], 那么dp[i][j] = dp[i-1][j], | ||
意思是如果当前字符不等, 那么就只能抛弃当前这个字符 | ||
递归公式中用到的dp[0][0] = 1, dp[i][0] = 0(把任意一个字符串变换为一个空串只有一个方法 | ||
``` | ||
|
||
|
||
10.单词分解Word Break | ||
|
||
``` | ||
字符串是否可以分解为给定的单词 | ||
For example, given | ||
s = "leetcode", | ||
dict = ["leet", "code"]. | ||
dp[i] 表示源串的前i个字符可以满足分割, 那么 dp[ j ] 满足分割的条件是存在k 使得 dp [k] && substr[k,j]在字典里. | ||
``` | ||
|