题目一:221. 最大正方形
dp[i][j]记录以(i, j)为右下角坐标的最大正方形边长,有动态规划方程:
dp[i][j] = min(dp[i][j-1], dp[i-1][j], dp[i-1][j-1])
// 221. 最大正方形
func maximalSquare(matrix [][]byte) int {
n, m := len(matrix), len(matrix[0])
dp := make([][]float64, n+1)
for i := range dp {
dp[i] = make([]float64, m+1)
}
var res int
for i := 0; i < n; i++ {
for j := 0; j < m; j++ {
if matrix[i][j] == '1' {
dp[i+1][j+1] = math.Min(math.Min(dp[i][j+1], dp[i+1][j]), dp[i][j])+1
if res < int(dp[i+1][j+1])*int(dp[i+1][j+1]) {
res = int(dp[i+1][j+1])*int(dp[i+1][j+1])
}
}
}
}
return res
}
时间复杂度O(nm),空间复杂度O(nm)
题目二:718. 最长重复子数组
i, j分别是nums1和nums2的下标,dp[i][j]记录nums1[i]和nums2[j]为重复子数组最后一个元素的长度,有动态规划方程:
dp[i][j] = dp[i-1][j-1]+1 (if nums1[i]==nums2[j])
// 718. 最长重复子数组
func findLength(nums1 []int, nums2 []int) int {
n, m := len(nums1), len(nums2)
dp := make([][]int, n+1)
var res int
for i := range dp {
dp[i] = make([]int, m+1)
}
for i := 0; i < n; i++ {
for j := 0; j < m; j++ {
if nums1[i] == nums2[j] {
dp[i+1][j+1] = dp[i][j] + 1
res = int(math.Max(float64(res), float64(dp[i+1][j+1])))
}
}
}
return res
}
题目三:64. 最小路径和
路径中的每一个位置(i, j)只能从左(i, j-1)或上(i-1, j)两个位置到达。则到达当前位置的最小路径和有动态规划方程:
dp[i][j] = min(dp[i][j-1], dp[i-1][j])+grid[i][j]
// 64. 最小路径和
func minPathSum(grid [][]int) int {
n, m := len(grid), len(grid[0])
dp := make([][]int, n+1)
for i := range dp {
dp[i] = make([]int, m+1)
if i == 0 {
for j := 0; j <= m; j++ {
dp[i][j] = math.MaxInt
}
}
dp[i][0] = math.MaxInt
}
for i := 0; i < n; i++ {
for j := 0; j < m; j++ {
if i == 0 && j == 0 {
dp[i+1][j+1] = grid[i][j]
continue
}
dp[i+1][j+1] = int(math.Min(float64(dp[i][j+1]), float64(dp[i+1][j]))) + grid[i][j]
}
}
return dp[n][m]
}