动态规划
基础篇 — 矩阵
一、不同路径
题目
题意
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
代码
方法一:
import math
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
return math.comb(m+n-2,n-1)
方法二:
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
s = [1] * n
for i in range(m-1):
for j in range(1,n):
s[j] = s[j-1] + s[j]
return s[-1]
方法三:
import itertools
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
s = [1] * n
for i in range(m-1):
s[:] = itertools.accumulate(s)
return s[-1]
二、最小路径和
题目
题意
给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
代码
class Solution:
def minPathSum(self, grid: List[List[int]]) -> int:
m = len(grid)
n = len(grid[0])
s = []
s[:] = itertools.accumulate(grid[0])
for i in range(1,m):
for j in range(n):
if j == 0:
s[j] = s[j] + grid[i][j]
else:
s[j] = min(s[j-1],s[j]) + grid[i][j]
return s[-1]
三、不同路径 II
题目
题意
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1 和 0 来表示。
代码
方法一:
class Solution:
def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
m = len(obstacleGrid)
n = len(obstacleGrid[0])
for i in range(m):
for j in range(n):
if obstacleGrid[i][j] == 1:
obstacleGrid[i][j] = 0
elif i == 0 and j == 0:
obstacleGrid[i][j] = 1
elif i == 0:
obstacleGrid[i][j] = obstacleGrid[i][j-1]
elif j == 0:
obstacleGrid[i][j] = obstacleGrid[i-1][j]
else:
obstacleGrid[i][j] = obstacleGrid[i-1][j] + obstacleGrid[i][j-1]
return obstacleGrid[-1][-1]
方法二:
class Solution:
def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
m = len(obstacleGrid)
n = len(obstacleGrid[0])
s = [0] * n
s[0] = 1 if obstacleGrid[0][0] == 0 else 0
for i in range(m):
for j in range(n):
if obstacleGrid[i][j] == 1:
s[j] = 0
elif j >= 1:
s[j] += s[j-1]
return s[-1]
四、三角形最小路径和
题目
题意
给定一个三角形 triangle ,找出自顶向下的最小路径和。
每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。也就是说,如果正位于当前行的下标 i ,那么下一步可以移动到下一行的下标 i 或 i + 1 。
代码
方法一:(自上而下)
class Solution:
def minimumTotal(self, triangle: List[List[int]]) -> int:
n = len(triangle)
if n == 1:
return triangle[0][0]
for i in range(1,n):
m = len(triangle[i])
for j in range(m):
if j == 0:
triangle[i][0] += triangle[i-1][0]
elif j == m-1:
triangle[i][-1] += triangle[i-1][-1]
else:
triangle[i][j] += min(triangle[i-1][j],triangle[i-1][j-1])
return min(triangle[-1])
方法二:(自下而上)
class Solution:
def minimumTotal(self, triangle: List[List[int]]) -> int:
n = len(triangle)
for i in range(n-2,-1,-1):
for j in range(len(triangle[i])):
triangle[i][j] += min(triangle[i+1][j],triangle[i+1][j+1])
return triangle[0][0]
五、下降路径最小和
题目
题意
给你一个 n x n 的 方形 整数数组 matrix ,请你找出并返回通过 matrix 的下降路径 的 最小和 。
下降路径 可以从第一行中的任何元素开始,并从每一行中选择一个元素。在下一行选择的元素和当前行所选元素最多相隔一列(即位于正下方或者沿对角线向左或者向右的第一个元素)。具体来说,位置 (row, col) 的下一个元素应当是 (row + 1, col - 1)、(row + 1, col) 或者 (row + 1, col + 1) 。
代码
方法一:
class Solution:
def minFallingPathSum(self, matrix: List[List[int]]) -> int:
n = len(matrix)
for i in range(n-2,-1,-1):
for j in range(n):
if j == 0:
matrix[i][j] += min(matrix[i+1][j],matrix[i+1][j+1])
elif j == n-1:
matrix[i][j] += min(matrix[i+1][j-1],matrix[i+1][j])
else:
matrix[i][j] += min(matrix[i+1][j-1],matrix[i+1][j],matrix[i+1][j+1])
return min(matrix[0])
方法二:
class Solution:
def minFallingPathSum(self, matrix: List[List[int]]) -> float:
n = len(matrix)
matrix[0] = [inf] + matrix[0] + [inf]
for i in range(1,n):
matrix[i] = [inf] + matrix[i] + [inf]
for j in range(1,n+1):
matrix[i][j] += min(matrix[i-1][j-1],matrix[i-1][j],matrix[i-1][j+1])
return min(matrix[-1])
六、最大正方形
题目
题意
在一个由 ‘0’ 和 ‘1’ 组成的二维矩阵内,找到只包含 ‘1’ 的最大正方形,并返回其面积。
代码
方法一:(暴力解法)
class Solution:
def maximalSquare(self, matrix: List[List[str]]) -> int:
s = 0
n = len(matrix)
m = len(matrix[0])
f = False
for i in range(n):
for j in range(m):
if matrix[i][j] == "1":
f = True
while f :
if i+s<n and j+s<m:
for a in range(i,i+s+1):
for b in range(j,j+s+1):
if matrix[a][b] == "0":
f = False
break
if not f :
break
else:
f = False
if f :
s += 1
return s**2
方法二:(动态规划,二维数组)
class Solution:
def maximalSquare(self, matrix: List[List[str]]) -> int:
m,n = len(matrix),len(matrix[0])
dp = [[0]*n for _ in range(m)]
s = 0
for i in range(m):
for j in range(n):
if matrix[i][j] == "1":
if i == 0 or j == 0:
dp[i][j] = 1
else:
dp[i][j] = min(dp[i-1][j-1],dp[i-1][j],dp[i][j-1]) + 1
s = max(s,dp[i][j])
return s**2
方法三:(动态规划,一维数组)
class Solution:
def maximalSquare(self, matrix: List[List[str]]) -> int:
m,n = len(matrix),len(matrix[0])
dp = [0]*n
s = 0
for i in range(m):
for j in range(n):
tmp = dp[j]
if matrix[i][j] == "1":
if j == 0:
dp[j] = 1
else:
dp[j] = min(prev,dp[j-1],dp[j]) + 1
s = max(s,dp[j])
else:
dp[j] = 0
prev = tmp
return s**2
方法四:(二进制思路)
class Solution:
def getWeight(self,num):
c = 0
while num > 0:
num &= num<<1
c += 1
return c
def maximalSquare(self, matrix: List[List[str]]) -> int:
s = [int("".join(i),base = 2) for i in matrix]
res,n = 0,len(s)
for i in range(n):
temp = s[i]
for j in range(i,n):
temp &= s[j]
w = self.getWeight(temp)
h = j-i+1
res = max(res,min(w,h))
return res**2