Files
hello-algo/codes/swift/chapter_dynamic_programming/edit_distance.swift
nuomi1 7359a7cb4b Review Swift codes (#1150)
* feat(swift): review for chapter_computational_complexity

* feat(swift): review for chapter_data_structure

* feat(swift): review for chapter_array_and_linkedlist

* feat(swift): review for chapter_stack_and_queue

* feat(swift): review for chapter_hashing

* feat(swift): review for chapter_tree

* feat(swift): add codes for heap article

* feat(swift): review for chapter_heap

* feat(swift): review for chapter_graph

* feat(swift): review for chapter_searching

* feat(swift): review for chapter_sorting

* feat(swift): review for chapter_divide_and_conquer

* feat(swift): review for chapter_backtracking

* feat(swift): review for chapter_dynamic_programming

* feat(swift): review for chapter_greedy

* feat(swift): review for utils

* feat(swift): update ci tool

* feat(swift): trailing closure

* feat(swift): array init

* feat(swift): map index
2024-03-20 21:15:39 +08:00

148 lines
4.7 KiB
Swift
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* File: edit_distance.swift
* Created Time: 2023-07-16
* Author: nuomi1 (nuomi1@qq.com)
*/
/* 编辑距离:暴力搜索 */
func editDistanceDFS(s: String, t: String, i: Int, j: Int) -> Int {
// 若 s 和 t 都为空,则返回 0
if i == 0, j == 0 {
return 0
}
// 若 s 为空,则返回 t 长度
if i == 0 {
return j
}
// 若 t 为空,则返回 s 长度
if j == 0 {
return i
}
// 若两字符相等,则直接跳过此两字符
if s.utf8CString[i - 1] == t.utf8CString[j - 1] {
return editDistanceDFS(s: s, t: t, i: i - 1, j: j - 1)
}
// 最少编辑步数 = 插入、删除、替换这三种操作的最少编辑步数 + 1
let insert = editDistanceDFS(s: s, t: t, i: i, j: j - 1)
let delete = editDistanceDFS(s: s, t: t, i: i - 1, j: j)
let replace = editDistanceDFS(s: s, t: t, i: i - 1, j: j - 1)
// 返回最少编辑步数
return min(min(insert, delete), replace) + 1
}
/* 编辑距离:记忆化搜索 */
func editDistanceDFSMem(s: String, t: String, mem: inout [[Int]], i: Int, j: Int) -> Int {
// 若 s 和 t 都为空,则返回 0
if i == 0, j == 0 {
return 0
}
// 若 s 为空,则返回 t 长度
if i == 0 {
return j
}
// 若 t 为空,则返回 s 长度
if j == 0 {
return i
}
// 若已有记录,则直接返回之
if mem[i][j] != -1 {
return mem[i][j]
}
// 若两字符相等,则直接跳过此两字符
if s.utf8CString[i - 1] == t.utf8CString[j - 1] {
return editDistanceDFS(s: s, t: t, i: i - 1, j: j - 1)
}
// 最少编辑步数 = 插入、删除、替换这三种操作的最少编辑步数 + 1
let insert = editDistanceDFS(s: s, t: t, i: i, j: j - 1)
let delete = editDistanceDFS(s: s, t: t, i: i - 1, j: j)
let replace = editDistanceDFS(s: s, t: t, i: i - 1, j: j - 1)
// 记录并返回最少编辑步数
mem[i][j] = min(min(insert, delete), replace) + 1
return mem[i][j]
}
/* 编辑距离:动态规划 */
func editDistanceDP(s: String, t: String) -> Int {
let n = s.utf8CString.count
let m = t.utf8CString.count
var dp = Array(repeating: Array(repeating: 0, count: m + 1), count: n + 1)
// 状态转移:首行首列
for i in 1 ... n {
dp[i][0] = i
}
for j in 1 ... m {
dp[0][j] = j
}
// 状态转移:其余行和列
for i in 1 ... n {
for j in 1 ... m {
if s.utf8CString[i - 1] == t.utf8CString[j - 1] {
// 若两字符相等,则直接跳过此两字符
dp[i][j] = dp[i - 1][j - 1]
} else {
// 最少编辑步数 = 插入、删除、替换这三种操作的最少编辑步数 + 1
dp[i][j] = min(min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1
}
}
}
return dp[n][m]
}
/* 编辑距离:空间优化后的动态规划 */
func editDistanceDPComp(s: String, t: String) -> Int {
let n = s.utf8CString.count
let m = t.utf8CString.count
var dp = Array(repeating: 0, count: m + 1)
// 状态转移:首行
for j in 1 ... m {
dp[j] = j
}
// 状态转移:其余行
for i in 1 ... n {
// 状态转移:首列
var leftup = dp[0] // 暂存 dp[i-1, j-1]
dp[0] = i
// 状态转移:其余列
for j in 1 ... m {
let temp = dp[j]
if s.utf8CString[i - 1] == t.utf8CString[j - 1] {
// 若两字符相等,则直接跳过此两字符
dp[j] = leftup
} else {
// 最少编辑步数 = 插入、删除、替换这三种操作的最少编辑步数 + 1
dp[j] = min(min(dp[j - 1], dp[j]), leftup) + 1
}
leftup = temp // 更新为下一轮的 dp[i-1, j-1]
}
}
return dp[m]
}
@main
enum EditDistance {
/* Driver Code */
static func main() {
let s = "bag"
let t = "pack"
let n = s.utf8CString.count
let m = t.utf8CString.count
// 暴力搜索
var res = editDistanceDFS(s: s, t: t, i: n, j: m)
print("将 \(s) 更改为 \(t) 最少需要编辑 \(res) 步")
// 记忆化搜索
var mem = Array(repeating: Array(repeating: -1, count: m + 1), count: n + 1)
res = editDistanceDFSMem(s: s, t: t, mem: &mem, i: n, j: m)
print("将 \(s) 更改为 \(t) 最少需要编辑 \(res) 步")
// 动态规划
res = editDistanceDP(s: s, t: t)
print("将 \(s) 更改为 \(t) 最少需要编辑 \(res) 步")
// 空间优化后的动态规划
res = editDistanceDPComp(s: s, t: t)
print("将 \(s) 更改为 \(t) 最少需要编辑 \(res) 步")
}
}