题目1:115. 不同的子序列
这里有个重点是, 如果字符相等 dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1]。
dp[i - 1][j - 1]好理解, 即选用了 s[i - 1], t[j - 1]。
dp[i - 1][j]对应的 其实就是不选用s[i - 1],那么就相当于 dp[i - 1][j]。
之所以存在 选用和不选用的区别 这里判断的是子序列的种类, 如果相等直接理解为选用的话, 就少计入了一部分情况。
比如下面的2:
class Solution {
func numDistinct(_ s: String, _ t: String) -> Int {
// dp[i][j] : s[0..<i] 中包含 t[0..<j] 的个数
// 如果 s[i - 1] == t[j - 1] : dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1]
// 否则 dp[i][j] = dp[i - 1][j]
if t.count == 0 { return 1 }
if s.count == 0 { return 0 }
var dp = Array(repeating: Array(repeating: 0, count: t.count + 1), count: s.count + 1)
for i in 0...s.count {
dp[i][0] = 1
}
var ss = Array(s)
var ts = Array(t)
for i in 1...s.count {
for j in 1...t.count {
if ss[i - 1] == ts[j - 1] {
dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1]
} else {
dp[i][j] = dp[i - 1][j]
}
}
}
return dp[s.count][t.count]
}
}
// 一维滚动。
class Solution {
func numDistinct(_ s: String, _ t: String) -> Int {
if t.count == 0 { return 1 }
if s.count == 0 { return 0 }
var dp = Array(repeating: 0, count: t.count + 1)
dp[0] = 1
let ss = Array(s)
let ts = Array(t)
for i in 1...s.count {
let lastDp = dp
for j in 1...t.count {
if ss[i - 1] == ts[j - 1] {
// 神奇的 原地修改变量值,避免复制。可以AC
dp[j] &+= lastDp[j - 1]
}
}
}
return dp[t.count]
}
}
题目2:583. 两个字符串的删除操作
如果字符相等, 那么不用操作。
如果字符不相等, 那么删除word1 或者 word2最后字符即可。
初始化是当前字符的个数。即删空。
class Solution {
func minDistance(_ word1: String, _ word2: String) -> Int {
var dp = Array(repeating: Array(repeating: 0, count: word2.count + 1), count: word1.count + 1)
for i in 0...word1.count { dp[i][0] = i }
for j in 0...word2.count { dp[0][j] = j }
let word1s = Array(word1)
let word2s = Array(word2)
for i in 1...word1.count {
for j in 1...word2.count {
if word1s[i - 1] == word2s[j - 1] {
dp[i][j] = dp[i - 1][j - 1]
} else {
dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1)
}
}
}
return dp[word1.count][word2.count]
}
}
题目3:72. 编辑距离
相较于 583. 两个字符串的删除操作 多了一个更换字符的选择。
class Solution {
func minDistance(_ word1: String, _ word2: String) -> Int {
var word1s = Array(word1)
var word2s = Array(word2)
var dp = Array(repeating: Array(repeating: 0, count: word2.count + 1), count: word1.count + 1)
for i in 0...word1.count { dp[i][0] = i }
for j in 0...word2.count { dp[0][j] = j }
if word1.isEmpty || word2.isEmpty { return dp[word1.count][word2.count] }
for i in 1...word1.count {
for j in 1...word2.count {
if word1s[i - 1] == word2s[j - 1] {
dp[i][j] = dp[i - 1][j - 1]
} else {
dp[i][j] = min(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]) + 1
}
}
}
return dp[word1.count][word2.count]
}
}