题目1:62.不同路径
// 自己写的,初始化的操作不得当,导致代码逻辑处理的复杂度变高了。
class Solution {
func uniquePaths(_ m: Int, _ n: Int) -> Int {
var dp = Array(repeating: Array(repeating: 0, count: n), count: m)
dp[0][0] = 1
for i in 0..<m {
for j in 0..<n {
if i == 0, j == 0 { continue }
if i > 0, j > 0 {
dp[i][j] = dp[i][j - 1] + dp[i - 1][j]
} else if i == 0 {
dp[i][j] = dp[i][j - 1]
} else {
dp[i][j] = dp[i - 1][j]
}
}
}
return dp[m - 1][n - 1]
}
}
// 初始化优化后
class Solution {
func uniquePaths(_ m: Int, _ n: Int) -> Int {
var dp = Array(repeating: Array(repeating: 0, count: n), count: m)
for i in 0..<m { dp[i][0] = 1 }
for i in 0..<n { dp[0][i] = 1 }
for i in 1..<m {
for j in 1..<n {
dp[i][j] = dp[i][j - 1] + dp[i - 1][j]
}
}
return dp[m - 1][n - 1]
}
}
题目2:63.不同路径II
// @lc code=start
class Solution {
// 注意审题:机器人每次只能向下或者向右移动一步
// 纠结了半天,为什么机器人不可以往回走...
func uniquePathsWithObstacles(_ obstacleGrid: [[Int]]) -> Int {
let m = obstacleGrid.count
let n = obstacleGrid[0].count
if obstacleGrid[0][0] == 1 || obstacleGrid[m - 1][n - 1] == 1 { return 0 }
var dp = Array(repeating: Array(repeating: 0, count: n), count: m)
for i in 0..<m {
if obstacleGrid[i][0] == 1 { break }
dp[i][0] = 1
}
for i in 0..<n {
if obstacleGrid[0][i] == 1 { break }
dp[0][i] = 1
}
for i in 1..<m {
for j in 1..<n {
if obstacleGrid[i][j] == 1 { continue }
dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
}
}
return dp[m - 1][n - 1]
}
}
// @lc code=end
// 空间省略
class Solution {
// 注意审题:机器人每次只能向下或者向右移动一步
// 纠结了半天,为什么机器人不可以往回走...
func uniquePathsWithObstacles(_ obstacleGrid: [[Int]]) -> Int {
let m = obstacleGrid.count
let n = obstacleGrid[0].count
if obstacleGrid[0][0] == 1 || obstacleGrid[m - 1][n - 1] == 1 { return 0 }
var dp = Array(repeating: 0, count: n)
for j in 0..<n {
if obstacleGrid[0][j] == 1 {
break // 碰到障碍物之后,后续的路径数都为 0
}
dp[j] = 1
}
for i in 1..<m {
for j in 0..<n {
if obstacleGrid[i][j] == 1 {
dp[j] = 0
} else if j > 0 { dp[j] += dp[j-1] }
}
}
return dp[n - 1]
}
}
题目3: 343.整数拆分
此题非常典型:
dp方程也有一定难度:定义为 dp[i] 为i拆分后的最大乘积。
所以递推方程为以下几个结果的最大者:
- dp[i]本身, 因为一直在遍历,所以保留最大者
- 将i拆成两个数 j * (i - j)
- 将i拆分成两个数之后,用dp[i - j]乘以 j。因为 dp[i - j]即为 i-j位置上的最大乘积。
因为要求n,数组下标从0开始,所以dp初始化n+1个元素。
初始化直接按照题目要求 dp[2] = 1, 越过 0 1两个元素即可。
遍历的时候从1开始,0没有意义。
// @lc code=start
class Solution {
func integerBreak(_ n: Int) -> Int {
if n <= 3 { return n - 1 }
var dp = Array(repeating: 0, count: n + 1)
dp[2] = 1
for i in 3...n {
for j in 1..<i {
dp[i] = max(dp[i], j * (i - j), j * dp[i - j])
}
}
return dp[n]
}
}
// @lc code=end
题目4:96.不同的二叉搜索树
// @lc code=start
class Solution {
func numTrees(_ n: Int) -> Int {
var dp = Array(repeating: 0, count: n + 1)
dp[0] = 1
// 这里的边界条件可以根据 i 为3进行推导: dp[0] * dp[2] + dp[1] * dp[1] + dp[2] * dp[0]
for i in 1...n {
for j in 1...i {
dp[i] += dp[j - 1] * dp[i - j]
}
}
return dp[n]
}
}
// @lc code=end