动态规划总结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
posted @ 2021-06-03 14:02  yuyinzi  阅读(97)  评论(0编辑  收藏  举报