动态规划的通用解法和案例

动态规划的通用解法和案例

两大要素

  • 最优子结构 (optimal substructure)
    • 一个问题的最优解包括它自问子问题的最优解
  • 重叠子问题 (overlapping subproblems)
    • 如使用递归算法,则某些子问题被反复访问

四个步骤

  1. Characterize the structure of an optimal solution. # 确定解的结构
  2. Recursively define the value of an optimal solution. # 写出递归关系
  3. Compute the value of an optimal solution, typically in a bottom-up fashion. # 自底向上实现
  4. (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[i1] 结尾的和为偶数的数组数目 + 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[i1] 结尾的和为奇数的数组数目。反之亦然

示例代码:

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

  1. 确定最优子结构
    定义序列 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,,xmY=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} Zk1 X m − 1 X_{m-1} Xm1 Y n − 1 Y_{n-1} Yn1 的LCS.
    • 如果 x m ≠ y n x_m\neq y_n xm=yn, 那么 Z Z Z X m − 1 X_{m-1} Xm1 Y n Y_{n} Yn X m X_{m} Xm Y n − 1 Y_{n-1} Yn1 的LCS.
  2. 写出递归解
    定义 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[i1,j1]+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,j1],c[i1,j])
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值