两大要素
- 最优子结构 (optimal substructure)
- 一个问题的最优解包括它自问子问题的最优解
- 重叠子问题 (overlapping subproblems)
- 如使用递归算法,则某些子问题被反复访问
四个步骤
- Characterize the structure of an optimal solution. # 确定解的结构
- Recursively define the value of an optimal solution. # 写出递归关系
- Compute the value of an optimal solution, typically in a bottom-up fashion. # 自底向上实现
- (Construct an optimal solution from computed information. )
案例
奇偶/正负问题
这类问题会给一个数组,要求返回与和为奇(偶)数/积为正(负)数有关的子数组相关的一些性质(数目,长度等),本质上是状态数为2的动态规划问题
1524. Number of Sub-arrays With Odd Sum
这道题的目的是找出所有和为奇数的子数组的数目。思路是找到递归关系:
- 对于位置 i i i ,如果 a r r [ i ] arr[i] arr[i] 是奇数,则以 a r r [ i ] arr[i] arr[i] 结尾的和为奇数的数组数目等于以 a r r [ i − 1 ] arr[i-1] arr[i−1] 结尾的和为偶数的数组数目 + 1 +1 +1 ( a r r [ i ] arr[i] arr[i] 本身也是一个子数组);以 a r r [ i ] arr[i] arr[i] 结尾的和为偶数的数组数目等于以 a r r [ i − 1 ] arr[i-1] arr[i−1] 结尾的和为奇数的数组数目。反之亦然
示例代码:
def numOfSubarrays(self, arr: List[int]) -> int:
if not arr:
return 0
even = 0
odd = 0
res = 0
for x in arr:
if x % 2 == 0:
even, odd = even + 1, odd
else:
even, odd = odd, even + 1
res += odd
return res % (10**9+7)
1567. Maximum Length of Subarray With Positive Product
这道题的目的是返回最长的积为正数的子数组的长度。思路同样是从递归关系入手
示例代码
def getMaxLen(self, nums: List[int]) -> int:
pos = 0
neg = 0
res = 0
for num in nums:
if num == 0:
pos = 0
neg = 0
elif num > 0:
pos += 1
neg = neg + 1 if neg else 0
else:
if neg == 0:
pos, neg = 0, pos + 1
else:
pos, neg = neg + 1, pos + 1
res = max(res, pos)
return res
二维DP
1143. Longest Common Subsequence
-
确定最优子结构
定义序列 X = ⟨ x 1 , x 2 , ⋯ , x m ⟩ , Y = ⟨ y 1 , y 2 , ⋯ , y n ⟩ X = \langle x_1, x_2, \cdots, x_m \rangle, Y= \langle y_1, y_2, \cdots, y_n \rangle X=⟨x1,x2,⋯,xm⟩,Y=⟨y1,y2,⋯,yn⟩, X , Y X, Y X,Y有最长公共子序列 Z = ⟨ z 1 , z 2 , ⋯ , z k ⟩ Z = \langle z_1, z_2, \cdots, z_k \rangle Z=⟨z1,z2,⋯,zk⟩.- 如果 x m = y n x_m=y_n xm=yn,那么 z k = x m = y n z_k = x_m = y_n zk=xm=yn 并且 Z k − 1 Z_{k-1} Zk−1 是 X m − 1 X_{m-1} Xm−1 和 Y n − 1 Y_{n-1} Yn−1 的LCS.
- 如果 x m ≠ y n x_m\neq y_n xm=yn, 那么 Z Z Z 是 X m − 1 X_{m-1} Xm−1 和 Y n Y_{n} Yn 或 X m X_{m} Xm 和 Y n − 1 Y_{n-1} Yn−1 的LCS.
-
写出递归解
定义 c [ i , j ] c[i,j] c[i,j] 为 X i X_i Xi 和 Y j Y_j Yj 的LCS长度.
- if
i
=
0
i=0
i=0 or
j
=
0
j=0
j=0
- c [ i , j ] = 0 c[i,j] = 0 c[i,j]=0
- else if
x
i
=
y
j
x_i = y_j
xi=yj
- c [ i , j ] = c [ i − 1 , j − 1 ] + 1 c[i,j] =c[i-1, j-1]+1 c[i,j]=c[i−1,j−1]+1
- else
- c [ i , j ] c[i,j] c[i,j] =max ( c [ i , j − 1 ] , c [ i − 1 , j ] ) (c[i, j-1], c[i-1,j]) (c[i,j−1],c[i−1,j])