动归题目分类汇总

来源:互联网 发布:淘宝一键复制宝贝上传 编辑:程序博客网 时间:2024/05/07 17:08

dp (包括递归)的思路是间接的,即不是直接的针对题目设计具体算法,而是递归,即规模为小的解直接知道,大规模的解是较小规模解的函数,一步一步递推而来。形象的可以说为填表法,第一个表项(一维表)或者第一行第一列(二维表)已知,其余表项可以一步一步推出来。

动规三要素

1)状态定义

2)状态转移方程,递推关系,

3)初始化,


九章的分类:

1 Matrix DP 代表题目

1)Number Triangle:  从三角顶到底边的路径最小和

状态定义:f[i][j] 为 从位置(i,j)到底边的路径最小和

递推式:f[i][j] = min(f[i + 1][j], f[i + 1][j + 1]) +triangle[i][j]

初始化:最后一行和三角形底边一致

2) Unique Path :一个矩阵,从左上角走到右下角的路径数

状态定义:f[i][j]为从(0,0)走到位置(i,j)的路径数

递推式:f[i][j] = f[i - 1][j] + f[i][j - 1]

初始化:第一行和第一列都是1

3) Unique Path II: 同上,但是矩阵里有些block site

递推式:f[i][j] = matrix[i][j] == 1 ? 0 : f[i - 1][j] + f[i][j + 1]

4) Minimum Path sum:求矩阵左上角到右下角的最小path sum,和Number Triangle很像

状态定义:f[i][j] 为左上角到位置(i, j)到path sum。

递推式:f[i][j] = min( f[i - 1][j], f[i][j - 1]) + matrix[i][j]


2 Sequence DP

1)Jump Game:是否能从A[0] 跳到A[n - 1]

状态定义:f[i]为是否能从A[0]跳到A[i]

递推式:f[i] = any( f[j] && A[j] >= i - j ) for j < i

初始化:f[0] = true

答案:f[n - 1]

2)Jump Game II 从A[0] 跳到A[n - 1] 最少多少步?

状态定义:f[i] 为 从A[0]跳到A[i] 最少多少步

递推式:f[i] = min( f[j] ) + 1  for j < i and A[j] >= i - j

初始化:f[0] = 0

解:f[n - 1]

3) Palindrome Partitioning II: 把一个字符串分割成全部是回文的子串最少需要多少次cut

状态定义:f[i] 为 s[i, n)分成回文子串的最少cut数

递推式:f[i] = min ( f [j+1] + 1)  for j >= i and j < n and s[i, j] 是回文

解:f[0]

4)Word Break:给定一个字符串和一个词典,问字符串是否能被完美分割为词典中的词

状态定义:f[i]为 前i个字符的串是否可以被完美分割

递推式:f[i] = any (s [j, i) is in the dict  and f [j] == true ) for j < i and i - j 在词典单词长度范围内

初始化:f[0] = true

答案:f[n]

5) LIS 问题

状态定义:f[i] 为以A[i] 结尾的最长递增子序列长度

递推式:f[i] = max (f [j] + 1) for j < i and A[i] >= A[j]

初始化:f[0] = 1

答案:max { f[i]  + 1}, i = 0,...n - 1


3 Two Sequences DP

1) Longest Common Subsequence 

状态定义:f[i][j] 为 s1 前i个字符的子串和s2前j个字符的子串的最长公共子序列

递推式:f[i][j] = f[i-1][j-1] + 1, when s1 [ i - 1] == s2 [j - 1]

f[i][j] = max ( f [i - 1] [ j], f [i][j - 1]), when s1[i-1] != s2[j-1]

初始化: 第一行和第一列为 0

答案:f[s1.size()][s2.size()]

2) Longest Common Substring

状态定义:f[i][j] 为s1的以第i个字符结尾的子串和s2的以第j个字符结尾的子串的最长公共子串长度

递推式:if s1[i-1] == s2[j-1], f[i][j] = f[i-1][j-1] + 1

else  f[i][j]= 0

初始化:第一行和第一列为0

答案:max{ f[i][j] }

3) Edit Distance

状态定义:f[i][j] 为s1的前i个字符的子串和 s2的前j个字符的子串的编辑距离

递推式:f[i][j] = f[i-1][j-1],when s1[i-1] == s2[j-1]

f[i][j] = min ( f[i-1][j-1] + 1, f[i][j-1] + 1, f[i-1][j] + 1 ), when s1[i-1] != s2[j-1]

初始化:第一行 每个元素值为列号j,第一列每个元素值为行号i

答案:f[s1.size()][s2.size()]

4) Distinct subsequences: 用一个字符串S的子序列构造另一个字符串T,有多少种方案?

状态定义:f[i][j]为 用S的前i个字符构的子序列构造T的前j个字符的子串的方案数

递推式:f[i][j] = f[i-1][j-1] + f[i-1][j], when S[i-1] == T[j-1]

f[i][j] = f[i-1][j], when S[i-1] != T[j-1]

初始化:第一行为0,但f[0][0] = 1,第一列为1(空串就用空子序列构造,总有一个方案)

答案:f[S.size()][T.size()]

5) Interleaving String:问一个字符串c是否可以用分别从字符串a、b取字符的方式构建

状态定义:f[i][j] 为 a的前i个字符的子串和b的前j个字符的子串是否可以构建出c的前i + j个字符的子串

递推式:f[i][j] = f[i-1][j] && a[i-1] == c[i+j-1] || f[i][j-1] && b[j-1] == c[i+j-1]

初始化:f[0][0] = true, 第一行其余部分 为 f[0][j] = b[j-1] == c[j-1], 第一列其余部分为f[i][0] = a[i-1] == c[i-1]

答案:f[a.size()][b.size()]


4 Backpack DP


0 0
原创粉丝点击