参考算法笔记
1.什么是动态规划
2.最大连续子列和
计算一个序列A[]
状态转移方程
dp[i]=max{A[i], dp[i-1]+A[i]}
3.最长不下降子序列
LIS: Longest Increasing Sequence
问题:在一个数字序列中,找一个最长的子序列(可以不连续),
使得这个子序列是非下降的。
方案一
对于每个元素都有选和不选,时间复杂度是 O ( 2 n ) O(2^n) O(2n)
方案二
状态转移方程:
dp[i]=max{1, dp[j]+1}
(j=0,1,…,i-1 && A[j]<=A[i])
例题:PAT A1045,讲解
4.最长公共子序列(LCS)
Longest Commom Subsequence, LCS
暴力方法:
对两个字符串m, n,每个字符都有选和不选,然后在比较,总时间复杂度为
O
(
2
m
+
n
∗
m
a
x
(
m
,
n
)
)
O(2^{m+n} * max(m, n))
O(2m+n∗max(m,n))。
dp方法:
dp[ i ][ j ]代表字符A的i号位和字符B的j号位之前的LCS。
d
p
[
i
]
[
j
]
=
{
d
p
[
i
−
1
]
[
j
−
1
]
+
1
,
A
[
i
]
=
B
[
i
]
m
a
x
(
d
p
[
i
−
1
]
[
j
]
,
d
p
[
i
]
[
j
−
1
]
)
,
A
[
i
]
!
=
B
[
i
]
dp[i][j]=\left\{ \begin{aligned} dp[i-1][j-1]+1, A[i] = B[i] \\ max(dp[i-1][j], dp[i][j-1]), A[i] != B[i] \end{aligned} \right.
dp[i][j]={dp[i−1][j−1]+1,A[i]=B[i]max(dp[i−1][j],dp[i][j−1]),A[i]!=B[i]
边界:
d
p
[
i
]
[
0
]
=
d
p
[
0
]
[
j
]
,
(
0
<
=
i
<
=
n
,
0
<
=
j
<
=
m
)
dp[i][0]=dp[0][j], (0<=i<=n, 0<=j<=m)
dp[i][0]=dp[0][j],(0<=i<=n,0<=j<=m)
时间复杂度O(m*n)。
5.最长回文连续子串
对于一个字符串S
- 暴力枚举:枚举子串两个端点[i, j], 然后判断回文,时间复杂度 O ( n 2 ∗ n ) O(n^2*n) O(n2∗n)
- 令dp[i][j]表示S[i]至S[j]的子串是否为回文串,则有状态转移方程:
d
p
[
i
]
[
j
]
=
{
d
p
[
i
+
1
]
[
j
−
1
]
+
1
,
S
[
i
]
=
=
S
[
i
]
0
,
S
[
i
]
!
=
S
[
i
]
dp[i][j]=\left\{ \begin{aligned} & dp[i+1][j-1]+1&, S[i] == S[i] \\ & 0 &, S[i] != S[i] \end{aligned} \right.
dp[i][j]={dp[i+1][j−1]+10,S[i]==S[i],S[i]!=S[i]
时间复杂度
O
(
n
3
)
O(n^3)
O(n3)。
应该考虑按照子串的初始长度进行枚举(从3到n/2)。
6.背包问题
6.1 01背包问题
有n件物品,每件物品的重量为w[i], 价值为c[i]。现在有一个容量为V的背包,使得背包内物品总价值最大,且每件物品只有一件。
令dp[i][v]表示前i件物品恰好装入容量v的背包里获得的价值。 ( 0 ≤ i ≤ n , 0 ≤ v ≤ V ) (0\le i \le n ,0 \le v \le V) (0≤i≤n,0≤v≤V)。
- 若不放第i件物品,则总价值等于前i-1的物品放入容量v的背包,即dp[i-1][v]。
- 若放第i件物品,则总价值是前i-1的物品放入容量v-w[i]的背包, 加上c[i],即dp[i-1][v-w[i]]+c[i]。
所以:
d
p
[
i
]
[
v
]
=
m
a
x
(
d
p
[
i
−
1
]
[
v
]
,
d
p
[
i
−
1
]
[
v
−
w
[
i
]
]
+
c
[
i
]
)
dp[i][v]=max(dp[i-1][v], dp[i-1][v-w[i]]+c[i])
dp[i][v]=max(dp[i−1][v],dp[i−1][v−w[i]]+c[i])
边界条件:dp[0][v]=0。 0<=v<=V。
时间复杂度O(n*V),空间复杂度也是的。
可以使用滚动数组进行空间复杂度的优化,但是v从V到w[i](逆序!)。
例题:https://blog.youkuaiyun.com/qq_44761480/article/details/99827377
6.2 完全背包问题
有n件物品,每件物品的重量为w[i], 价值为c[i]。现在有一个容量为V的背包,使得背包内物品总价值最大,每件物品有无数件。
令dp[i][v]表示前i件物品恰好装入容量v的背包里获得的价值。 ( 0 ≤ i ≤ n , 0 ≤ v ≤ V ) (0\le i \le n ,0 \le v \le V) (0≤i≤n,0≤v≤V)。
- 若不放第i件物品,则总价值等于前i-1的物品放入容量v的背包,即dp[i-1][v]。
2. 若放第i件物品,则总价值是前i的物品放入容量v-w[i]的背包, 加上c[i],即dp[i][v-w[i]]+c[i]。注意这里i并不是放了多少件,而是前i件物品。
所以:状态转移方程 d p [ i ] [ v ] = m a x ( d p [ i − 1 ] [ v ] , d p [ i ] [ v − w [ i ] ] + c [ i ] ) dp[i][v]=max(dp[i-1][v], dp[i][v-w[i]]+c[i]) dp[i][v]=max(dp[i−1][v],dp[i][v−w[i]]+c[i])
边界条件: d p [ 0 ] [ v ] = 0 。 0 < = v < = V dp[0][v]=0。 0<=v<=V dp[0][v]=0。0<=v<=V。
改成一维形式:
d
p
[
v
]
=
m
a
x
(
d
p
[
v
]
,
d
p
[
v
−
w
[
i
]
]
+
c
[
i
]
)
dp[v]=max(dp[v], dp[v-w[i]]+c[i])
dp[v]=max(dp[v],dp[v−w[i]]+c[i])
注意:v的枚举顺序是正向枚举。