动态规划总结3 多维dp
前序题目的共性是只需要利用一维数组就可以解决,但有的情况下是需要利用二维数组才能解答.也就是说,需要两个变量i
,j
才能确定当前的状态.
从经典的机器人走路开始吧.
Leetcode 62. Unique Paths
给定一个m*n
的地图,机器人只能向右或者向下运动.从左上角到右下角有几种走法?
因为是m*n
的图,所以会很自然地想到用二维数组来表示每一个点的方案.那么,在(i,j)
的可能到达路径就是从左边和上边出发到达该点的和:
class Solution(object):
def uniquePaths(self, m, n):
"""
:type m: int
:type n: int
:rtype: int
"""
dp = [[0 for j in range(n)] for i in range(m)]
for i in range(m):
dp[i][0] = 1
for j in range(n):
dp[0][j] = 1
for i in range(1, m):
for j in range(1, n):
dp[i][j] = dp[i-1][j] + dp[i][j-1]
return dp[-1][-1]
Leetcode 63. Unique Paths II
作为上一题的变种,新增了图中存在障碍点需要绕过的情况,也可以采用类似的做法,只是在初始化的时候有所变化.
Example:
Input: obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
Output: 2
Explanation: There is one obstacle in the middle of the 3x3 grid above.
There are two ways to reach the bottom-right corner:
1. Right -> Right -> Down -> Down
2. Down -> Down -> Right -> Right
解答:
class Solution(object):
def uniquePathsWithObstacles(self, obstacleGrid):
"""
:type obstacleGrid: List[List[int]]
:rtype: int
"""
m, n = len(obstacleGrid), len(obstacleGrid[0])
dp = [[0 for j in range(n)] for i in range(m)]
for i in range(m):
if obstacleGrid[i][0] == 1:
break
else:
dp[i][0] = 1
for j in range(n):
if obstacleGrid[0][j] == 1:
break
else:
dp[0][j] = 1
for i in range(1, m):
for j in range(1, n):
if obstacleGrid[i][j] != 1:
dp[i][j] = dp[i-1][j] + dp[i][j-1]
return dp[-1][-1]
为了方便初始化和处理越界,通常会采用多增加一行:
class Solution(object):
def uniquePathsWithObstacles(self, obstacleGrid):
"""
:type obstacleGrid: List[List[int]]
:rtype: int
"""
m, n = len(obstacleGrid), len(obstacleGrid[0])
dp = [[0 for j in range(n+1)] for i in range(m+1)]
dp[0][1] = 1
for i in range(1, m+1):
for j in range(1, n+1):
if obstacleGrid[i-1][j-1] != 1:
dp[i][j] = dp[i-1][j] + dp[i][j-1]
return dp[-1][-1]
相比而言,如果计算两个数组的公共最长子序列略微没有那么强的暗示了.但是只有数组A
的第i
个位置的值等于数组B
的第j
个位置的值,也需要用两个变量才能确定状态,因而也可以采用这种解法.
Leetcode 718. Maximum Length of Repeated Subarray
计算两个数组的公共最长子序列,Example:
Input: nums1 = [1,2,3,2,1], nums2 = [3,2,1,4,5]
Output: 3
Explanation: The repeated subarray with maximum length is [3,2,1].
假设dp[i][j]
代表以nums1
的第i
个位置和nums2
的第j
个位置结尾时的最长公共子序列的值,那么:
dp[i][j] = dp[i-1][j-1] + 1 仅当nums1[i] = nums2[j]时成立
else
dp[i][j] = 0
这里也采用多增加一行(比如下图的X
)的方式,针对例子,它的dp
矩阵如下:
代码如下:
class Solution(object):
def findLength(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: int
"""
m, n = len(nums1), len(nums2)
matrix = [[0 for j in range(m+1)] for i in range(n+1)]
res = 0
for i in range(n):
for j in range(m):
if nums1[j] == nums2[i]:
matrix[i+1][j+1] = matrix[i][j] + 1
res = max(res, matrix[i+1][j+1])
return res