mirror of
https://github.com/krahets/hello-algo.git
synced 2025-02-02 22:43:50 +08:00
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
This commit is contained in:
parent
300a781fab
commit
7359a7cb4b
4
.github/workflows/swift.yml
vendored
4
.github/workflows/swift.yml
vendored
@ -19,9 +19,9 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest]
|
os: [ubuntu-latest, macos-latest]
|
||||||
swift: ["5.9", "5.8.1", "5.7.3"]
|
swift: ["5.10", "5.9", "5.8"]
|
||||||
steps:
|
steps:
|
||||||
- uses: swift-actions/setup-swift@v1
|
- uses: swift-actions/setup-swift@v2
|
||||||
with:
|
with:
|
||||||
swift-version: ${{ matrix.swift }}
|
swift-version: ${{ matrix.swift }}
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
@ -41,6 +41,7 @@ let package = Package(
|
|||||||
.executable(name: "binary_search_tree", targets: ["binary_search_tree"]),
|
.executable(name: "binary_search_tree", targets: ["binary_search_tree"]),
|
||||||
.executable(name: "avl_tree", targets: ["avl_tree"]),
|
.executable(name: "avl_tree", targets: ["avl_tree"]),
|
||||||
// chapter_heap
|
// chapter_heap
|
||||||
|
.executable(name: "heap", targets: ["heap"]),
|
||||||
.executable(name: "my_heap", targets: ["my_heap"]),
|
.executable(name: "my_heap", targets: ["my_heap"]),
|
||||||
.executable(name: "top_k", targets: ["top_k"]),
|
.executable(name: "top_k", targets: ["top_k"]),
|
||||||
// chapter_graph
|
// chapter_graph
|
||||||
@ -143,6 +144,7 @@ let package = Package(
|
|||||||
.executableTarget(name: "binary_search_tree", dependencies: ["utils"], path: "chapter_tree", sources: ["binary_search_tree.swift"]),
|
.executableTarget(name: "binary_search_tree", dependencies: ["utils"], path: "chapter_tree", sources: ["binary_search_tree.swift"]),
|
||||||
.executableTarget(name: "avl_tree", dependencies: ["utils"], path: "chapter_tree", sources: ["avl_tree.swift"]),
|
.executableTarget(name: "avl_tree", dependencies: ["utils"], path: "chapter_tree", sources: ["avl_tree.swift"]),
|
||||||
// chapter_heap
|
// chapter_heap
|
||||||
|
.executableTarget(name: "heap", dependencies: ["utils", .product(name: "HeapModule", package: "swift-collections")], path: "chapter_heap", sources: ["heap.swift"]),
|
||||||
.executableTarget(name: "my_heap", dependencies: ["utils"], path: "chapter_heap", sources: ["my_heap.swift"]),
|
.executableTarget(name: "my_heap", dependencies: ["utils"], path: "chapter_heap", sources: ["my_heap.swift"]),
|
||||||
.executableTarget(name: "top_k", dependencies: ["utils", .product(name: "HeapModule", package: "swift-collections")], path: "chapter_heap", sources: ["top_k.swift"]),
|
.executableTarget(name: "top_k", dependencies: ["utils", .product(name: "HeapModule", package: "swift-collections")], path: "chapter_heap", sources: ["top_k.swift"]),
|
||||||
// chapter_graph
|
// chapter_graph
|
||||||
|
@ -54,6 +54,11 @@ func traverse(nums: [Int]) {
|
|||||||
for num in nums {
|
for num in nums {
|
||||||
count += num
|
count += num
|
||||||
}
|
}
|
||||||
|
// 同时遍历数据索引和元素
|
||||||
|
for (i, num) in nums.enumerated() {
|
||||||
|
count += nums[i]
|
||||||
|
count += num
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 在数组中查找指定元素 */
|
/* 在数组中查找指定元素 */
|
||||||
|
@ -22,7 +22,6 @@ func remove(n0: ListNode) {
|
|||||||
let P = n0.next
|
let P = n0.next
|
||||||
let n1 = P?.next
|
let n1 = P?.next
|
||||||
n0.next = n1
|
n0.next = n1
|
||||||
P?.next = nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 访问链表中索引为 index 的节点 */
|
/* 访问链表中索引为 index 的节点 */
|
||||||
|
@ -7,12 +7,15 @@
|
|||||||
/* 列表类 */
|
/* 列表类 */
|
||||||
class MyList {
|
class MyList {
|
||||||
private var arr: [Int] // 数组(存储列表元素)
|
private var arr: [Int] // 数组(存储列表元素)
|
||||||
private var _capacity = 10 // 列表容量
|
private var _capacity: Int // 列表容量
|
||||||
private var _size = 0 // 列表长度(当前元素数量)
|
private var _size: Int // 列表长度(当前元素数量)
|
||||||
private let extendRatio = 2 // 每次列表扩容的倍数
|
private let extendRatio: Int // 每次列表扩容的倍数
|
||||||
|
|
||||||
/* 构造方法 */
|
/* 构造方法 */
|
||||||
init() {
|
init() {
|
||||||
|
_capacity = 10
|
||||||
|
_size = 0
|
||||||
|
extendRatio = 2
|
||||||
arr = Array(repeating: 0, count: _capacity)
|
arr = Array(repeating: 0, count: _capacity)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,7 +32,7 @@ class MyList {
|
|||||||
/* 访问元素 */
|
/* 访问元素 */
|
||||||
func get(index: Int) -> Int {
|
func get(index: Int) -> Int {
|
||||||
// 索引如果越界则抛出错误,下同
|
// 索引如果越界则抛出错误,下同
|
||||||
if index < 0 || index >= _size {
|
if index < 0 || index >= size() {
|
||||||
fatalError("索引越界")
|
fatalError("索引越界")
|
||||||
}
|
}
|
||||||
return arr[index]
|
return arr[index]
|
||||||
@ -37,7 +40,7 @@ class MyList {
|
|||||||
|
|
||||||
/* 更新元素 */
|
/* 更新元素 */
|
||||||
func set(index: Int, num: Int) {
|
func set(index: Int, num: Int) {
|
||||||
if index < 0 || index >= _size {
|
if index < 0 || index >= size() {
|
||||||
fatalError("索引越界")
|
fatalError("索引越界")
|
||||||
}
|
}
|
||||||
arr[index] = num
|
arr[index] = num
|
||||||
@ -46,25 +49,25 @@ class MyList {
|
|||||||
/* 在尾部添加元素 */
|
/* 在尾部添加元素 */
|
||||||
func add(num: Int) {
|
func add(num: Int) {
|
||||||
// 元素数量超出容量时,触发扩容机制
|
// 元素数量超出容量时,触发扩容机制
|
||||||
if _size == _capacity {
|
if size() == capacity() {
|
||||||
extendCapacity()
|
extendCapacity()
|
||||||
}
|
}
|
||||||
arr[_size] = num
|
arr[size()] = num
|
||||||
// 更新元素数量
|
// 更新元素数量
|
||||||
_size += 1
|
_size += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 在中间插入元素 */
|
/* 在中间插入元素 */
|
||||||
func insert(index: Int, num: Int) {
|
func insert(index: Int, num: Int) {
|
||||||
if index < 0 || index >= _size {
|
if index < 0 || index >= size() {
|
||||||
fatalError("索引越界")
|
fatalError("索引越界")
|
||||||
}
|
}
|
||||||
// 元素数量超出容量时,触发扩容机制
|
// 元素数量超出容量时,触发扩容机制
|
||||||
if _size == _capacity {
|
if size() == capacity() {
|
||||||
extendCapacity()
|
extendCapacity()
|
||||||
}
|
}
|
||||||
// 将索引 index 以及之后的元素都向后移动一位
|
// 将索引 index 以及之后的元素都向后移动一位
|
||||||
for j in sequence(first: _size - 1, next: { $0 >= index + 1 ? $0 - 1 : nil }) {
|
for j in (index ..< size()).reversed() {
|
||||||
arr[j + 1] = arr[j]
|
arr[j + 1] = arr[j]
|
||||||
}
|
}
|
||||||
arr[index] = num
|
arr[index] = num
|
||||||
@ -75,12 +78,12 @@ class MyList {
|
|||||||
/* 删除元素 */
|
/* 删除元素 */
|
||||||
@discardableResult
|
@discardableResult
|
||||||
func remove(index: Int) -> Int {
|
func remove(index: Int) -> Int {
|
||||||
if index < 0 || index >= _size {
|
if index < 0 || index >= size() {
|
||||||
fatalError("索引越界")
|
fatalError("索引越界")
|
||||||
}
|
}
|
||||||
let num = arr[index]
|
let num = arr[index]
|
||||||
// 将将索引 index 之后的元素都向前移动一位
|
// 将将索引 index 之后的元素都向前移动一位
|
||||||
for j in index ..< (_size - 1) {
|
for j in index ..< (size() - 1) {
|
||||||
arr[j] = arr[j + 1]
|
arr[j] = arr[j + 1]
|
||||||
}
|
}
|
||||||
// 更新元素数量
|
// 更新元素数量
|
||||||
@ -92,18 +95,14 @@ class MyList {
|
|||||||
/* 列表扩容 */
|
/* 列表扩容 */
|
||||||
func extendCapacity() {
|
func extendCapacity() {
|
||||||
// 新建一个长度为原数组 extendRatio 倍的新数组,并将原数组复制到新数组
|
// 新建一个长度为原数组 extendRatio 倍的新数组,并将原数组复制到新数组
|
||||||
arr = arr + Array(repeating: 0, count: _capacity * (extendRatio - 1))
|
arr = arr + Array(repeating: 0, count: capacity() * (extendRatio - 1))
|
||||||
// 更新列表容量
|
// 更新列表容量
|
||||||
_capacity = arr.count
|
_capacity = arr.count
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 将列表转换为数组 */
|
/* 将列表转换为数组 */
|
||||||
func toArray() -> [Int] {
|
func toArray() -> [Int] {
|
||||||
var arr = Array(repeating: 0, count: _size)
|
Array(arr.prefix(size()))
|
||||||
for i in 0 ..< _size {
|
|
||||||
arr[i] = get(index: i)
|
|
||||||
}
|
|
||||||
return arr
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ func backtrack(state: inout [Int], target: Int, choices: [Int], start: Int, res:
|
|||||||
}
|
}
|
||||||
// 遍历所有选择
|
// 遍历所有选择
|
||||||
// 剪枝二:从 start 开始遍历,避免生成重复子集
|
// 剪枝二:从 start 开始遍历,避免生成重复子集
|
||||||
for i in stride(from: start, to: choices.count, by: 1) {
|
for i in choices.indices.dropFirst(start) {
|
||||||
// 剪枝一:若子集和超过 target ,则直接结束循环
|
// 剪枝一:若子集和超过 target ,则直接结束循环
|
||||||
// 这是因为数组已排序,后边元素更大,子集和一定超过 target
|
// 这是因为数组已排序,后边元素更大,子集和一定超过 target
|
||||||
if target - choices[i] < 0 {
|
if target - choices[i] < 0 {
|
||||||
|
@ -12,7 +12,7 @@ func backtrack(state: inout [Int], target: Int, total: Int, choices: [Int], res:
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 遍历所有选择
|
// 遍历所有选择
|
||||||
for i in stride(from: 0, to: choices.count, by: 1) {
|
for i in choices.indices {
|
||||||
// 剪枝:若子集和超过 target ,则跳过该选择
|
// 剪枝:若子集和超过 target ,则跳过该选择
|
||||||
if total + choices[i] > target {
|
if total + choices[i] > target {
|
||||||
continue
|
continue
|
||||||
|
@ -14,7 +14,7 @@ func backtrack(state: inout [Int], target: Int, choices: [Int], start: Int, res:
|
|||||||
// 遍历所有选择
|
// 遍历所有选择
|
||||||
// 剪枝二:从 start 开始遍历,避免生成重复子集
|
// 剪枝二:从 start 开始遍历,避免生成重复子集
|
||||||
// 剪枝三:从 start 开始遍历,避免重复选择同一元素
|
// 剪枝三:从 start 开始遍历,避免重复选择同一元素
|
||||||
for i in stride(from: start, to: choices.count, by: 1) {
|
for i in choices.indices.dropFirst(start) {
|
||||||
// 剪枝一:若子集和超过 target ,则直接结束循环
|
// 剪枝一:若子集和超过 target ,则直接结束循环
|
||||||
// 这是因为数组已排序,后边元素更大,子集和一定超过 target
|
// 这是因为数组已排序,后边元素更大,子集和一定超过 target
|
||||||
if target - choices[i] < 0 {
|
if target - choices[i] < 0 {
|
||||||
|
@ -22,7 +22,7 @@ func forLoopRecur(n: Int) -> Int {
|
|||||||
var stack: [Int] = []
|
var stack: [Int] = []
|
||||||
var res = 0
|
var res = 0
|
||||||
// 递:递归调用
|
// 递:递归调用
|
||||||
for i in stride(from: n, to: 0, by: -1) {
|
for i in (1 ... n).reversed() {
|
||||||
// 通过“入栈操作”模拟“递”
|
// 通过“入栈操作”模拟“递”
|
||||||
stack.append(i)
|
stack.append(i)
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ func quadratic(n: Int) -> Int {
|
|||||||
func bubbleSort(nums: inout [Int]) -> Int {
|
func bubbleSort(nums: inout [Int]) -> Int {
|
||||||
var count = 0 // 计数器
|
var count = 0 // 计数器
|
||||||
// 外循环:未排序区间为 [0, i]
|
// 外循环:未排序区间为 [0, i]
|
||||||
for i in stride(from: nums.count - 1, to: 0, by: -1) {
|
for i in nums.indices.dropFirst().reversed() {
|
||||||
// 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
|
// 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
|
||||||
for j in 0 ..< i {
|
for j in 0 ..< i {
|
||||||
if nums[j] > nums[j + 1] {
|
if nums[j] > nums[j + 1] {
|
||||||
|
@ -26,9 +26,8 @@ func dfs(nums: [Int], target: Int, i: Int, j: Int) -> Int {
|
|||||||
|
|
||||||
/* 二分查找 */
|
/* 二分查找 */
|
||||||
func binarySearch(nums: [Int], target: Int) -> Int {
|
func binarySearch(nums: [Int], target: Int) -> Int {
|
||||||
let n = nums.count
|
|
||||||
// 求解问题 f(0, n-1)
|
// 求解问题 f(0, n-1)
|
||||||
return dfs(nums: nums, target: target, i: 0, j: n - 1)
|
dfs(nums: nums, target: target, i: nums.startIndex, j: nums.endIndex - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@main
|
@main
|
||||||
|
@ -28,7 +28,7 @@ func dfs(preorder: [Int], inorderMap: [Int: Int], i: Int, l: Int, r: Int) -> Tre
|
|||||||
func buildTree(preorder: [Int], inorder: [Int]) -> TreeNode? {
|
func buildTree(preorder: [Int], inorder: [Int]) -> TreeNode? {
|
||||||
// 初始化哈希表,存储 inorder 元素到索引的映射
|
// 初始化哈希表,存储 inorder 元素到索引的映射
|
||||||
let inorderMap = inorder.enumerated().reduce(into: [:]) { $0[$1.element] = $1.offset }
|
let inorderMap = inorder.enumerated().reduce(into: [:]) { $0[$1.element] = $1.offset }
|
||||||
return dfs(preorder: preorder, inorderMap: inorderMap, i: 0, l: 0, r: inorder.count - 1)
|
return dfs(preorder: preorder, inorderMap: inorderMap, i: inorder.startIndex, l: inorder.startIndex, r: inorder.endIndex - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@main
|
@main
|
||||||
|
@ -17,7 +17,7 @@ func climbingStairsConstraintDP(n: Int) -> Int {
|
|||||||
dp[2][1] = 0
|
dp[2][1] = 0
|
||||||
dp[2][2] = 1
|
dp[2][2] = 1
|
||||||
// 状态转移:从较小子问题逐步求解较大子问题
|
// 状态转移:从较小子问题逐步求解较大子问题
|
||||||
for i in stride(from: 3, through: n, by: 1) {
|
for i in 3 ... n {
|
||||||
dp[i][1] = dp[i - 1][2]
|
dp[i][1] = dp[i - 1][2]
|
||||||
dp[i][2] = dp[i - 2][1] + dp[i - 2][2]
|
dp[i][2] = dp[i - 2][1] + dp[i - 2][2]
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ func climbingStairsDP(n: Int) -> Int {
|
|||||||
dp[1] = 1
|
dp[1] = 1
|
||||||
dp[2] = 2
|
dp[2] = 2
|
||||||
// 状态转移:从较小子问题逐步求解较大子问题
|
// 状态转移:从较小子问题逐步求解较大子问题
|
||||||
for i in stride(from: 3, through: n, by: 1) {
|
for i in 3 ... n {
|
||||||
dp[i] = dp[i - 1] + dp[i - 2]
|
dp[i] = dp[i - 1] + dp[i - 2]
|
||||||
}
|
}
|
||||||
return dp[n]
|
return dp[n]
|
||||||
@ -28,7 +28,7 @@ func climbingStairsDPComp(n: Int) -> Int {
|
|||||||
}
|
}
|
||||||
var a = 1
|
var a = 1
|
||||||
var b = 2
|
var b = 2
|
||||||
for _ in stride(from: 3, through: n, by: 1) {
|
for _ in 3 ... n {
|
||||||
(a, b) = (b, a + b)
|
(a, b) = (b, a + b)
|
||||||
}
|
}
|
||||||
return b
|
return b
|
||||||
|
@ -11,12 +11,12 @@ func coinChangeDP(coins: [Int], amt: Int) -> Int {
|
|||||||
// 初始化 dp 表
|
// 初始化 dp 表
|
||||||
var dp = Array(repeating: Array(repeating: 0, count: amt + 1), count: n + 1)
|
var dp = Array(repeating: Array(repeating: 0, count: amt + 1), count: n + 1)
|
||||||
// 状态转移:首行首列
|
// 状态转移:首行首列
|
||||||
for a in stride(from: 1, through: amt, by: 1) {
|
for a in 1 ... amt {
|
||||||
dp[0][a] = MAX
|
dp[0][a] = MAX
|
||||||
}
|
}
|
||||||
// 状态转移:其余行和列
|
// 状态转移:其余行和列
|
||||||
for i in stride(from: 1, through: n, by: 1) {
|
for i in 1 ... n {
|
||||||
for a in stride(from: 1, through: amt, by: 1) {
|
for a in 1 ... amt {
|
||||||
if coins[i - 1] > a {
|
if coins[i - 1] > a {
|
||||||
// 若超过目标金额,则不选硬币 i
|
// 若超过目标金额,则不选硬币 i
|
||||||
dp[i][a] = dp[i - 1][a]
|
dp[i][a] = dp[i - 1][a]
|
||||||
@ -37,8 +37,8 @@ func coinChangeDPComp(coins: [Int], amt: Int) -> Int {
|
|||||||
var dp = Array(repeating: MAX, count: amt + 1)
|
var dp = Array(repeating: MAX, count: amt + 1)
|
||||||
dp[0] = 0
|
dp[0] = 0
|
||||||
// 状态转移
|
// 状态转移
|
||||||
for i in stride(from: 1, through: n, by: 1) {
|
for i in 1 ... n {
|
||||||
for a in stride(from: 1, through: amt, by: 1) {
|
for a in 1 ... amt {
|
||||||
if coins[i - 1] > a {
|
if coins[i - 1] > a {
|
||||||
// 若超过目标金额,则不选硬币 i
|
// 若超过目标金额,则不选硬币 i
|
||||||
dp[a] = dp[a]
|
dp[a] = dp[a]
|
||||||
|
@ -10,12 +10,12 @@ func coinChangeIIDP(coins: [Int], amt: Int) -> Int {
|
|||||||
// 初始化 dp 表
|
// 初始化 dp 表
|
||||||
var dp = Array(repeating: Array(repeating: 0, count: amt + 1), count: n + 1)
|
var dp = Array(repeating: Array(repeating: 0, count: amt + 1), count: n + 1)
|
||||||
// 初始化首列
|
// 初始化首列
|
||||||
for i in stride(from: 0, through: n, by: 1) {
|
for i in 0 ... n {
|
||||||
dp[i][0] = 1
|
dp[i][0] = 1
|
||||||
}
|
}
|
||||||
// 状态转移
|
// 状态转移
|
||||||
for i in stride(from: 1, through: n, by: 1) {
|
for i in 1 ... n {
|
||||||
for a in stride(from: 1, through: amt, by: 1) {
|
for a in 1 ... amt {
|
||||||
if coins[i - 1] > a {
|
if coins[i - 1] > a {
|
||||||
// 若超过目标金额,则不选硬币 i
|
// 若超过目标金额,则不选硬币 i
|
||||||
dp[i][a] = dp[i - 1][a]
|
dp[i][a] = dp[i - 1][a]
|
||||||
@ -35,8 +35,8 @@ func coinChangeIIDPComp(coins: [Int], amt: Int) -> Int {
|
|||||||
var dp = Array(repeating: 0, count: amt + 1)
|
var dp = Array(repeating: 0, count: amt + 1)
|
||||||
dp[0] = 1
|
dp[0] = 1
|
||||||
// 状态转移
|
// 状态转移
|
||||||
for i in stride(from: 1, through: n, by: 1) {
|
for i in 1 ... n {
|
||||||
for a in stride(from: 1, through: amt, by: 1) {
|
for a in 1 ... amt {
|
||||||
if coins[i - 1] > a {
|
if coins[i - 1] > a {
|
||||||
// 若超过目标金额,则不选硬币 i
|
// 若超过目标金额,则不选硬币 i
|
||||||
dp[a] = dp[a]
|
dp[a] = dp[a]
|
||||||
|
@ -67,15 +67,15 @@ func editDistanceDP(s: String, t: String) -> Int {
|
|||||||
let m = t.utf8CString.count
|
let m = t.utf8CString.count
|
||||||
var dp = Array(repeating: Array(repeating: 0, count: m + 1), count: n + 1)
|
var dp = Array(repeating: Array(repeating: 0, count: m + 1), count: n + 1)
|
||||||
// 状态转移:首行首列
|
// 状态转移:首行首列
|
||||||
for i in stride(from: 1, through: n, by: 1) {
|
for i in 1 ... n {
|
||||||
dp[i][0] = i
|
dp[i][0] = i
|
||||||
}
|
}
|
||||||
for j in stride(from: 1, through: m, by: 1) {
|
for j in 1 ... m {
|
||||||
dp[0][j] = j
|
dp[0][j] = j
|
||||||
}
|
}
|
||||||
// 状态转移:其余行和列
|
// 状态转移:其余行和列
|
||||||
for i in stride(from: 1, through: n, by: 1) {
|
for i in 1 ... n {
|
||||||
for j in stride(from: 1, through: m, by: 1) {
|
for j in 1 ... m {
|
||||||
if s.utf8CString[i - 1] == t.utf8CString[j - 1] {
|
if s.utf8CString[i - 1] == t.utf8CString[j - 1] {
|
||||||
// 若两字符相等,则直接跳过此两字符
|
// 若两字符相等,则直接跳过此两字符
|
||||||
dp[i][j] = dp[i - 1][j - 1]
|
dp[i][j] = dp[i - 1][j - 1]
|
||||||
@ -94,16 +94,16 @@ func editDistanceDPComp(s: String, t: String) -> Int {
|
|||||||
let m = t.utf8CString.count
|
let m = t.utf8CString.count
|
||||||
var dp = Array(repeating: 0, count: m + 1)
|
var dp = Array(repeating: 0, count: m + 1)
|
||||||
// 状态转移:首行
|
// 状态转移:首行
|
||||||
for j in stride(from: 1, through: m, by: 1) {
|
for j in 1 ... m {
|
||||||
dp[j] = j
|
dp[j] = j
|
||||||
}
|
}
|
||||||
// 状态转移:其余行
|
// 状态转移:其余行
|
||||||
for i in stride(from: 1, through: n, by: 1) {
|
for i in 1 ... n {
|
||||||
// 状态转移:首列
|
// 状态转移:首列
|
||||||
var leftup = dp[0] // 暂存 dp[i-1, j-1]
|
var leftup = dp[0] // 暂存 dp[i-1, j-1]
|
||||||
dp[0] = i
|
dp[0] = i
|
||||||
// 状态转移:其余列
|
// 状态转移:其余列
|
||||||
for j in stride(from: 1, through: m, by: 1) {
|
for j in 1 ... m {
|
||||||
let temp = dp[j]
|
let temp = dp[j]
|
||||||
if s.utf8CString[i - 1] == t.utf8CString[j - 1] {
|
if s.utf8CString[i - 1] == t.utf8CString[j - 1] {
|
||||||
// 若两字符相等,则直接跳过此两字符
|
// 若两字符相等,则直接跳过此两字符
|
||||||
|
@ -49,8 +49,8 @@ func knapsackDP(wgt: [Int], val: [Int], cap: Int) -> Int {
|
|||||||
// 初始化 dp 表
|
// 初始化 dp 表
|
||||||
var dp = Array(repeating: Array(repeating: 0, count: cap + 1), count: n + 1)
|
var dp = Array(repeating: Array(repeating: 0, count: cap + 1), count: n + 1)
|
||||||
// 状态转移
|
// 状态转移
|
||||||
for i in stride(from: 1, through: n, by: 1) {
|
for i in 1 ... n {
|
||||||
for c in stride(from: 1, through: cap, by: 1) {
|
for c in 1 ... cap {
|
||||||
if wgt[i - 1] > c {
|
if wgt[i - 1] > c {
|
||||||
// 若超过背包容量,则不选物品 i
|
// 若超过背包容量,则不选物品 i
|
||||||
dp[i][c] = dp[i - 1][c]
|
dp[i][c] = dp[i - 1][c]
|
||||||
@ -69,9 +69,9 @@ func knapsackDPComp(wgt: [Int], val: [Int], cap: Int) -> Int {
|
|||||||
// 初始化 dp 表
|
// 初始化 dp 表
|
||||||
var dp = Array(repeating: 0, count: cap + 1)
|
var dp = Array(repeating: 0, count: cap + 1)
|
||||||
// 状态转移
|
// 状态转移
|
||||||
for i in stride(from: 1, through: n, by: 1) {
|
for i in 1 ... n {
|
||||||
// 倒序遍历
|
// 倒序遍历
|
||||||
for c in stride(from: cap, through: 1, by: -1) {
|
for c in (1 ... cap).reversed() {
|
||||||
if wgt[i - 1] <= c {
|
if wgt[i - 1] <= c {
|
||||||
// 不选和选物品 i 这两种方案的较大值
|
// 不选和选物品 i 这两种方案的较大值
|
||||||
dp[c] = max(dp[c], dp[c - wgt[i - 1]] + val[i - 1])
|
dp[c] = max(dp[c], dp[c - wgt[i - 1]] + val[i - 1])
|
||||||
|
@ -16,7 +16,7 @@ func minCostClimbingStairsDP(cost: [Int]) -> Int {
|
|||||||
dp[1] = cost[1]
|
dp[1] = cost[1]
|
||||||
dp[2] = cost[2]
|
dp[2] = cost[2]
|
||||||
// 状态转移:从较小子问题逐步求解较大子问题
|
// 状态转移:从较小子问题逐步求解较大子问题
|
||||||
for i in stride(from: 3, through: n, by: 1) {
|
for i in 3 ... n {
|
||||||
dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i]
|
dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i]
|
||||||
}
|
}
|
||||||
return dp[n]
|
return dp[n]
|
||||||
@ -29,7 +29,7 @@ func minCostClimbingStairsDPComp(cost: [Int]) -> Int {
|
|||||||
return cost[n]
|
return cost[n]
|
||||||
}
|
}
|
||||||
var (a, b) = (cost[1], cost[2])
|
var (a, b) = (cost[1], cost[2])
|
||||||
for i in stride(from: 3, through: n, by: 1) {
|
for i in 3 ... n {
|
||||||
(a, b) = (b, min(a, b) + cost[i])
|
(a, b) = (b, min(a, b) + cost[i])
|
||||||
}
|
}
|
||||||
return b
|
return b
|
||||||
|
@ -51,16 +51,16 @@ func minPathSumDP(grid: [[Int]]) -> Int {
|
|||||||
var dp = Array(repeating: Array(repeating: 0, count: m), count: n)
|
var dp = Array(repeating: Array(repeating: 0, count: m), count: n)
|
||||||
dp[0][0] = grid[0][0]
|
dp[0][0] = grid[0][0]
|
||||||
// 状态转移:首行
|
// 状态转移:首行
|
||||||
for j in stride(from: 1, to: m, by: 1) {
|
for j in 1 ..< m {
|
||||||
dp[0][j] = dp[0][j - 1] + grid[0][j]
|
dp[0][j] = dp[0][j - 1] + grid[0][j]
|
||||||
}
|
}
|
||||||
// 状态转移:首列
|
// 状态转移:首列
|
||||||
for i in stride(from: 1, to: n, by: 1) {
|
for i in 1 ..< n {
|
||||||
dp[i][0] = dp[i - 1][0] + grid[i][0]
|
dp[i][0] = dp[i - 1][0] + grid[i][0]
|
||||||
}
|
}
|
||||||
// 状态转移:其余行和列
|
// 状态转移:其余行和列
|
||||||
for i in stride(from: 1, to: n, by: 1) {
|
for i in 1 ..< n {
|
||||||
for j in stride(from: 1, to: m, by: 1) {
|
for j in 1 ..< m {
|
||||||
dp[i][j] = min(dp[i][j - 1], dp[i - 1][j]) + grid[i][j]
|
dp[i][j] = min(dp[i][j - 1], dp[i - 1][j]) + grid[i][j]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -75,15 +75,15 @@ func minPathSumDPComp(grid: [[Int]]) -> Int {
|
|||||||
var dp = Array(repeating: 0, count: m)
|
var dp = Array(repeating: 0, count: m)
|
||||||
// 状态转移:首行
|
// 状态转移:首行
|
||||||
dp[0] = grid[0][0]
|
dp[0] = grid[0][0]
|
||||||
for j in stride(from: 1, to: m, by: 1) {
|
for j in 1 ..< m {
|
||||||
dp[j] = dp[j - 1] + grid[0][j]
|
dp[j] = dp[j - 1] + grid[0][j]
|
||||||
}
|
}
|
||||||
// 状态转移:其余行
|
// 状态转移:其余行
|
||||||
for i in stride(from: 1, to: n, by: 1) {
|
for i in 1 ..< n {
|
||||||
// 状态转移:首列
|
// 状态转移:首列
|
||||||
dp[0] = dp[0] + grid[i][0]
|
dp[0] = dp[0] + grid[i][0]
|
||||||
// 状态转移:其余列
|
// 状态转移:其余列
|
||||||
for j in stride(from: 1, to: m, by: 1) {
|
for j in 1 ..< m {
|
||||||
dp[j] = min(dp[j - 1], dp[j]) + grid[i][j]
|
dp[j] = min(dp[j - 1], dp[j]) + grid[i][j]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,8 @@ func unboundedKnapsackDP(wgt: [Int], val: [Int], cap: Int) -> Int {
|
|||||||
// 初始化 dp 表
|
// 初始化 dp 表
|
||||||
var dp = Array(repeating: Array(repeating: 0, count: cap + 1), count: n + 1)
|
var dp = Array(repeating: Array(repeating: 0, count: cap + 1), count: n + 1)
|
||||||
// 状态转移
|
// 状态转移
|
||||||
for i in stride(from: 1, through: n, by: 1) {
|
for i in 1 ... n {
|
||||||
for c in stride(from: 1, through: cap, by: 1) {
|
for c in 1 ... cap {
|
||||||
if wgt[i - 1] > c {
|
if wgt[i - 1] > c {
|
||||||
// 若超过背包容量,则不选物品 i
|
// 若超过背包容量,则不选物品 i
|
||||||
dp[i][c] = dp[i - 1][c]
|
dp[i][c] = dp[i - 1][c]
|
||||||
@ -30,8 +30,8 @@ func unboundedKnapsackDPComp(wgt: [Int], val: [Int], cap: Int) -> Int {
|
|||||||
// 初始化 dp 表
|
// 初始化 dp 表
|
||||||
var dp = Array(repeating: 0, count: cap + 1)
|
var dp = Array(repeating: 0, count: cap + 1)
|
||||||
// 状态转移
|
// 状态转移
|
||||||
for i in stride(from: 1, through: n, by: 1) {
|
for i in 1 ... n {
|
||||||
for c in stride(from: 1, through: cap, by: 1) {
|
for c in 1 ... cap {
|
||||||
if wgt[i - 1] > c {
|
if wgt[i - 1] > c {
|
||||||
// 若超过背包容量,则不选物品 i
|
// 若超过背包容量,则不选物品 i
|
||||||
dp[c] = dp[c]
|
dp[c] = dp[c]
|
||||||
|
@ -43,8 +43,8 @@ public class GraphAdjList {
|
|||||||
fatalError("参数错误")
|
fatalError("参数错误")
|
||||||
}
|
}
|
||||||
// 删除边 vet1 - vet2
|
// 删除边 vet1 - vet2
|
||||||
adjList[vet1]?.removeAll(where: { $0 == vet2 })
|
adjList[vet1]?.removeAll { $0 == vet2 }
|
||||||
adjList[vet2]?.removeAll(where: { $0 == vet1 })
|
adjList[vet2]?.removeAll { $0 == vet1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 添加顶点 */
|
/* 添加顶点 */
|
||||||
@ -65,19 +65,16 @@ public class GraphAdjList {
|
|||||||
adjList.removeValue(forKey: vet)
|
adjList.removeValue(forKey: vet)
|
||||||
// 遍历其他顶点的链表,删除所有包含 vet 的边
|
// 遍历其他顶点的链表,删除所有包含 vet 的边
|
||||||
for key in adjList.keys {
|
for key in adjList.keys {
|
||||||
adjList[key]?.removeAll(where: { $0 == vet })
|
adjList[key]?.removeAll { $0 == vet }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 打印邻接表 */
|
/* 打印邻接表 */
|
||||||
public func print() {
|
public func print() {
|
||||||
Swift.print("邻接表 =")
|
Swift.print("邻接表 =")
|
||||||
for pair in adjList {
|
for (vertex, list) in adjList {
|
||||||
var tmp: [Int] = []
|
let list = list.map { $0.val }
|
||||||
for vertex in pair.value {
|
Swift.print("\(vertex.val): \(list),")
|
||||||
tmp.append(vertex.val)
|
|
||||||
}
|
|
||||||
Swift.print("\(pair.key.val): \(tmp),")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ func fractionalKnapsack(wgt: [Int], val: [Int], cap: Int) -> Double {
|
|||||||
// 创建物品列表,包含两个属性:重量、价值
|
// 创建物品列表,包含两个属性:重量、价值
|
||||||
var items = zip(wgt, val).map { Item(w: $0, v: $1) }
|
var items = zip(wgt, val).map { Item(w: $0, v: $1) }
|
||||||
// 按照单位价值 item.v / item.w 从高到低进行排序
|
// 按照单位价值 item.v / item.w 从高到低进行排序
|
||||||
items.sort(by: { -(Double($0.v) / Double($0.w)) < -(Double($1.v) / Double($1.w)) })
|
items.sort { -(Double($0.v) / Double($0.w)) < -(Double($1.v) / Double($1.w)) }
|
||||||
// 循环贪心选择
|
// 循环贪心选择
|
||||||
var res = 0.0
|
var res = 0.0
|
||||||
var cap = cap
|
var cap = cap
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
/* 最大容量:贪心 */
|
/* 最大容量:贪心 */
|
||||||
func maxCapacity(ht: [Int]) -> Int {
|
func maxCapacity(ht: [Int]) -> Int {
|
||||||
// 初始化 i, j,使其分列数组两端
|
// 初始化 i, j,使其分列数组两端
|
||||||
var i = 0, j = ht.count - 1
|
var i = ht.startIndex, j = ht.endIndex - 1
|
||||||
// 初始最大容量为 0
|
// 初始最大容量为 0
|
||||||
var res = 0
|
var res = 0
|
||||||
// 循环贪心选择,直至两板相遇
|
// 循环贪心选择,直至两板相遇
|
||||||
|
@ -8,13 +8,11 @@ import utils
|
|||||||
|
|
||||||
/* 基于数组实现的哈希表 */
|
/* 基于数组实现的哈希表 */
|
||||||
class ArrayHashMap {
|
class ArrayHashMap {
|
||||||
private var buckets: [Pair?] = []
|
private var buckets: [Pair?]
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
// 初始化数组,包含 100 个桶
|
// 初始化数组,包含 100 个桶
|
||||||
for _ in 0 ..< 100 {
|
buckets = Array(repeating: nil, count: 100)
|
||||||
buckets.append(nil)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 哈希函数 */
|
/* 哈希函数 */
|
||||||
@ -46,35 +44,17 @@ class ArrayHashMap {
|
|||||||
|
|
||||||
/* 获取所有键值对 */
|
/* 获取所有键值对 */
|
||||||
func pairSet() -> [Pair] {
|
func pairSet() -> [Pair] {
|
||||||
var pairSet: [Pair] = []
|
buckets.compactMap { $0 }
|
||||||
for pair in buckets {
|
|
||||||
if let pair = pair {
|
|
||||||
pairSet.append(pair)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pairSet
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 获取所有键 */
|
/* 获取所有键 */
|
||||||
func keySet() -> [Int] {
|
func keySet() -> [Int] {
|
||||||
var keySet: [Int] = []
|
buckets.compactMap { $0?.key }
|
||||||
for pair in buckets {
|
|
||||||
if let pair = pair {
|
|
||||||
keySet.append(pair.key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return keySet
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 获取所有值 */
|
/* 获取所有值 */
|
||||||
func valueSet() -> [String] {
|
func valueSet() -> [String] {
|
||||||
var valueSet: [String] = []
|
buckets.compactMap { $0?.val }
|
||||||
for pair in buckets {
|
|
||||||
if let pair = pair {
|
|
||||||
valueSet.append(pair.val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return valueSet
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 打印哈希表 */
|
/* 打印哈希表 */
|
||||||
|
@ -30,7 +30,7 @@ class HashMapChaining {
|
|||||||
|
|
||||||
/* 负载因子 */
|
/* 负载因子 */
|
||||||
func loadFactor() -> Double {
|
func loadFactor() -> Double {
|
||||||
Double(size / capacity)
|
Double(size) / Double(capacity)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 查询操作 */
|
/* 查询操作 */
|
||||||
@ -76,9 +76,10 @@ class HashMapChaining {
|
|||||||
for (pairIndex, pair) in bucket.enumerated() {
|
for (pairIndex, pair) in bucket.enumerated() {
|
||||||
if pair.key == key {
|
if pair.key == key {
|
||||||
buckets[index].remove(at: pairIndex)
|
buckets[index].remove(at: pairIndex)
|
||||||
}
|
|
||||||
}
|
|
||||||
size -= 1
|
size -= 1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 扩容哈希表 */
|
/* 扩容哈希表 */
|
||||||
|
@ -32,7 +32,7 @@ class HashMapOpenAddressing {
|
|||||||
|
|
||||||
/* 负载因子 */
|
/* 负载因子 */
|
||||||
func loadFactor() -> Double {
|
func loadFactor() -> Double {
|
||||||
Double(size / capacity)
|
Double(size) / Double(capacity)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 搜索 key 对应的桶索引 */
|
/* 搜索 key 对应的桶索引 */
|
||||||
|
62
codes/swift/chapter_heap/heap.swift
Normal file
62
codes/swift/chapter_heap/heap.swift
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/**
|
||||||
|
* File: heap.swift
|
||||||
|
* Created Time: 2024-03-17
|
||||||
|
* Author: nuomi1 (nuomi1@qq.com)
|
||||||
|
*/
|
||||||
|
|
||||||
|
import HeapModule
|
||||||
|
import utils
|
||||||
|
|
||||||
|
func testPush(heap: inout Heap<Int>, val: Int) {
|
||||||
|
heap.insert(val)
|
||||||
|
print("\n元素 \(val) 入堆后\n")
|
||||||
|
PrintUtil.printHeap(queue: heap.unordered)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testPop(heap: inout Heap<Int>) {
|
||||||
|
let val = heap.removeMax()
|
||||||
|
print("\n堆顶元素 \(val) 出堆后\n")
|
||||||
|
PrintUtil.printHeap(queue: heap.unordered)
|
||||||
|
}
|
||||||
|
|
||||||
|
@main
|
||||||
|
enum _Heap {
|
||||||
|
/* Driver Code */
|
||||||
|
static func main() {
|
||||||
|
/* 初始化堆 */
|
||||||
|
// Swift 的 Heap 类型同时支持最大堆和最小堆
|
||||||
|
var heap = Heap<Int>()
|
||||||
|
|
||||||
|
/* 元素入堆 */
|
||||||
|
testPush(heap: &heap, val: 1)
|
||||||
|
testPush(heap: &heap, val: 3)
|
||||||
|
testPush(heap: &heap, val: 2)
|
||||||
|
testPush(heap: &heap, val: 5)
|
||||||
|
testPush(heap: &heap, val: 4)
|
||||||
|
|
||||||
|
/* 获取堆顶元素 */
|
||||||
|
let peek = heap.max()
|
||||||
|
print("\n堆顶元素为 \(peek!)\n")
|
||||||
|
|
||||||
|
/* 堆顶元素出堆 */
|
||||||
|
testPop(heap: &heap)
|
||||||
|
testPop(heap: &heap)
|
||||||
|
testPop(heap: &heap)
|
||||||
|
testPop(heap: &heap)
|
||||||
|
testPop(heap: &heap)
|
||||||
|
|
||||||
|
/* 获取堆大小 */
|
||||||
|
let size = heap.count
|
||||||
|
print("\n堆元素数量为 \(size)\n")
|
||||||
|
|
||||||
|
/* 判断堆是否为空 */
|
||||||
|
let isEmpty = heap.isEmpty
|
||||||
|
print("\n堆是否为空 \(isEmpty)\n")
|
||||||
|
|
||||||
|
/* 输入列表并建堆 */
|
||||||
|
// 时间复杂度为 O(n) ,而非 O(nlogn)
|
||||||
|
let heap2 = Heap([1, 3, 2, 5, 4])
|
||||||
|
print("\n输入列表并建立堆后")
|
||||||
|
PrintUtil.printHeap(queue: heap2.unordered)
|
||||||
|
}
|
||||||
|
}
|
@ -15,7 +15,7 @@ class MaxHeap {
|
|||||||
// 将列表元素原封不动添加进堆
|
// 将列表元素原封不动添加进堆
|
||||||
maxHeap = nums
|
maxHeap = nums
|
||||||
// 堆化除叶节点以外的其他所有节点
|
// 堆化除叶节点以外的其他所有节点
|
||||||
for i in stride(from: parent(i: size() - 1), through: 0, by: -1) {
|
for i in (0 ... parent(i: size() - 1)).reversed() {
|
||||||
siftDown(i: i)
|
siftDown(i: i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ func topKHeap(nums: [Int], k: Int) -> [Int] {
|
|||||||
// 初始化一个小顶堆,并将前 k 个元素建堆
|
// 初始化一个小顶堆,并将前 k 个元素建堆
|
||||||
var heap = Heap(nums.prefix(k))
|
var heap = Heap(nums.prefix(k))
|
||||||
// 从第 k+1 个元素开始,保持堆的长度为 k
|
// 从第 k+1 个元素开始,保持堆的长度为 k
|
||||||
for i in stride(from: k, to: nums.count, by: 1) {
|
for i in nums.indices.dropFirst(k) {
|
||||||
// 若当前元素大于堆顶元素,则将堆顶元素出堆、当前元素入堆
|
// 若当前元素大于堆顶元素,则将堆顶元素出堆、当前元素入堆
|
||||||
if nums[i] > heap.min()! {
|
if nums[i] > heap.min()! {
|
||||||
_ = heap.removeMin()
|
_ = heap.removeMin()
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
/* 二分查找(双闭区间) */
|
/* 二分查找(双闭区间) */
|
||||||
func binarySearch(nums: [Int], target: Int) -> Int {
|
func binarySearch(nums: [Int], target: Int) -> Int {
|
||||||
// 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素
|
// 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素
|
||||||
var i = 0
|
var i = nums.startIndex
|
||||||
var j = nums.count - 1
|
var j = nums.endIndex - 1
|
||||||
// 循环,当搜索区间为空时跳出(当 i > j 时为空)
|
// 循环,当搜索区间为空时跳出(当 i > j 时为空)
|
||||||
while i <= j {
|
while i <= j {
|
||||||
let m = i + (j - i) / 2 // 计算中点索引 m
|
let m = i + (j - i) / 2 // 计算中点索引 m
|
||||||
@ -27,8 +27,8 @@ func binarySearch(nums: [Int], target: Int) -> Int {
|
|||||||
/* 二分查找(左闭右开区间) */
|
/* 二分查找(左闭右开区间) */
|
||||||
func binarySearchLCRO(nums: [Int], target: Int) -> Int {
|
func binarySearchLCRO(nums: [Int], target: Int) -> Int {
|
||||||
// 初始化左闭右开区间 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1
|
// 初始化左闭右开区间 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1
|
||||||
var i = 0
|
var i = nums.startIndex
|
||||||
var j = nums.count
|
var j = nums.endIndex
|
||||||
// 循环,当搜索区间为空时跳出(当 i = j 时为空)
|
// 循环,当搜索区间为空时跳出(当 i = j 时为空)
|
||||||
while i < j {
|
while i < j {
|
||||||
let m = i + (j - i) / 2 // 计算中点索引 m
|
let m = i + (j - i) / 2 // 计算中点索引 m
|
||||||
|
@ -11,7 +11,7 @@ func binarySearchLeftEdge(nums: [Int], target: Int) -> Int {
|
|||||||
// 等价于查找 target 的插入点
|
// 等价于查找 target 的插入点
|
||||||
let i = binarySearchInsertion(nums: nums, target: target)
|
let i = binarySearchInsertion(nums: nums, target: target)
|
||||||
// 未找到 target ,返回 -1
|
// 未找到 target ,返回 -1
|
||||||
if i == nums.count || nums[i] != target {
|
if i == nums.endIndex || nums[i] != target {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
// 找到 target ,返回索引 i
|
// 找到 target ,返回索引 i
|
||||||
|
@ -6,7 +6,9 @@
|
|||||||
|
|
||||||
/* 二分查找插入点(无重复元素) */
|
/* 二分查找插入点(无重复元素) */
|
||||||
func binarySearchInsertionSimple(nums: [Int], target: Int) -> Int {
|
func binarySearchInsertionSimple(nums: [Int], target: Int) -> Int {
|
||||||
var i = 0, j = nums.count - 1 // 初始化双闭区间 [0, n-1]
|
// 初始化双闭区间 [0, n-1]
|
||||||
|
var i = nums.startIndex
|
||||||
|
var j = nums.endIndex - 1
|
||||||
while i <= j {
|
while i <= j {
|
||||||
let m = i + (j - i) / 2 // 计算中点索引 m
|
let m = i + (j - i) / 2 // 计算中点索引 m
|
||||||
if nums[m] < target {
|
if nums[m] < target {
|
||||||
@ -23,7 +25,9 @@ func binarySearchInsertionSimple(nums: [Int], target: Int) -> Int {
|
|||||||
|
|
||||||
/* 二分查找插入点(存在重复元素) */
|
/* 二分查找插入点(存在重复元素) */
|
||||||
public func binarySearchInsertion(nums: [Int], target: Int) -> Int {
|
public func binarySearchInsertion(nums: [Int], target: Int) -> Int {
|
||||||
var i = 0, j = nums.count - 1 // 初始化双闭区间 [0, n-1]
|
// 初始化双闭区间 [0, n-1]
|
||||||
|
var i = nums.startIndex
|
||||||
|
var j = nums.endIndex - 1
|
||||||
while i <= j {
|
while i <= j {
|
||||||
let m = i + (j - i) / 2 // 计算中点索引 m
|
let m = i + (j - i) / 2 // 计算中点索引 m
|
||||||
if nums[m] < target {
|
if nums[m] < target {
|
||||||
|
@ -7,14 +7,12 @@
|
|||||||
/* 冒泡排序 */
|
/* 冒泡排序 */
|
||||||
func bubbleSort(nums: inout [Int]) {
|
func bubbleSort(nums: inout [Int]) {
|
||||||
// 外循环:未排序区间为 [0, i]
|
// 外循环:未排序区间为 [0, i]
|
||||||
for i in stride(from: nums.count - 1, to: 0, by: -1) {
|
for i in nums.indices.dropFirst().reversed() {
|
||||||
// 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
|
// 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
|
||||||
for j in stride(from: 0, to: i, by: 1) {
|
for j in 0 ..< i {
|
||||||
if nums[j] > nums[j + 1] {
|
if nums[j] > nums[j + 1] {
|
||||||
// 交换 nums[j] 与 nums[j + 1]
|
// 交换 nums[j] 与 nums[j + 1]
|
||||||
let tmp = nums[j]
|
nums.swapAt(j, j + 1)
|
||||||
nums[j] = nums[j + 1]
|
|
||||||
nums[j + 1] = tmp
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -23,14 +21,12 @@ func bubbleSort(nums: inout [Int]) {
|
|||||||
/* 冒泡排序(标志优化)*/
|
/* 冒泡排序(标志优化)*/
|
||||||
func bubbleSortWithFlag(nums: inout [Int]) {
|
func bubbleSortWithFlag(nums: inout [Int]) {
|
||||||
// 外循环:未排序区间为 [0, i]
|
// 外循环:未排序区间为 [0, i]
|
||||||
for i in stride(from: nums.count - 1, to: 0, by: -1) {
|
for i in nums.indices.dropFirst().reversed() {
|
||||||
var flag = false // 初始化标志位
|
var flag = false // 初始化标志位
|
||||||
for j in stride(from: 0, to: i, by: 1) {
|
for j in 0 ..< i {
|
||||||
if nums[j] > nums[j + 1] {
|
if nums[j] > nums[j + 1] {
|
||||||
// 交换 nums[j] 与 nums[j + 1]
|
// 交换 nums[j] 与 nums[j + 1]
|
||||||
let tmp = nums[j]
|
nums.swapAt(j, j + 1)
|
||||||
nums[j] = nums[j + 1]
|
|
||||||
nums[j + 1] = tmp
|
|
||||||
flag = true // 记录交换元素
|
flag = true // 记录交换元素
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ func bucketSort(nums: inout [Double]) {
|
|||||||
for bucket in buckets {
|
for bucket in buckets {
|
||||||
for num in bucket {
|
for num in bucket {
|
||||||
nums[i] = num
|
nums[i] = num
|
||||||
nums.formIndex(after: &i)
|
i += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,8 @@ func countingSortNaive(nums: inout [Int]) {
|
|||||||
}
|
}
|
||||||
// 3. 遍历 counter ,将各元素填入原数组 nums
|
// 3. 遍历 counter ,将各元素填入原数组 nums
|
||||||
var i = 0
|
var i = 0
|
||||||
for num in stride(from: 0, to: m + 1, by: 1) {
|
for num in 0 ..< m + 1 {
|
||||||
for _ in stride(from: 0, to: counter[num], by: 1) {
|
for _ in 0 ..< counter[num] {
|
||||||
nums[i] = num
|
nums[i] = num
|
||||||
i += 1
|
i += 1
|
||||||
}
|
}
|
||||||
@ -38,19 +38,19 @@ func countingSort(nums: inout [Int]) {
|
|||||||
}
|
}
|
||||||
// 3. 求 counter 的前缀和,将“出现次数”转换为“尾索引”
|
// 3. 求 counter 的前缀和,将“出现次数”转换为“尾索引”
|
||||||
// 即 counter[num]-1 是 num 在 res 中最后一次出现的索引
|
// 即 counter[num]-1 是 num 在 res 中最后一次出现的索引
|
||||||
for i in stride(from: 0, to: m, by: 1) {
|
for i in 0 ..< m {
|
||||||
counter[i + 1] += counter[i]
|
counter[i + 1] += counter[i]
|
||||||
}
|
}
|
||||||
// 4. 倒序遍历 nums ,将各元素填入结果数组 res
|
// 4. 倒序遍历 nums ,将各元素填入结果数组 res
|
||||||
// 初始化数组 res 用于记录结果
|
// 初始化数组 res 用于记录结果
|
||||||
var res = Array(repeating: 0, count: nums.count)
|
var res = Array(repeating: 0, count: nums.count)
|
||||||
for i in stride(from: nums.count - 1, through: 0, by: -1) {
|
for i in nums.indices.reversed() {
|
||||||
let num = nums[i]
|
let num = nums[i]
|
||||||
res[counter[num] - 1] = num // 将 num 放置到对应索引处
|
res[counter[num] - 1] = num // 将 num 放置到对应索引处
|
||||||
counter[num] -= 1 // 令前缀和自减 1 ,得到下次放置 num 的索引
|
counter[num] -= 1 // 令前缀和自减 1 ,得到下次放置 num 的索引
|
||||||
}
|
}
|
||||||
// 使用结果数组 res 覆盖原数组 nums
|
// 使用结果数组 res 覆盖原数组 nums
|
||||||
for i in stride(from: 0, to: nums.count, by: 1) {
|
for i in nums.indices {
|
||||||
nums[i] = res[i]
|
nums[i] = res[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ func heapSort(nums: inout [Int]) {
|
|||||||
siftDown(nums: &nums, n: nums.count, i: i)
|
siftDown(nums: &nums, n: nums.count, i: i)
|
||||||
}
|
}
|
||||||
// 从堆中提取最大元素,循环 n-1 轮
|
// 从堆中提取最大元素,循环 n-1 轮
|
||||||
for i in stride(from: nums.count - 1, to: 0, by: -1) {
|
for i in nums.indices.dropFirst().reversed() {
|
||||||
// 交换根节点与最右叶节点(交换首元素与尾元素)
|
// 交换根节点与最右叶节点(交换首元素与尾元素)
|
||||||
nums.swapAt(0, i)
|
nums.swapAt(0, i)
|
||||||
// 以根节点为起点,从顶至底进行堆化
|
// 以根节点为起点,从顶至底进行堆化
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
/* 插入排序 */
|
/* 插入排序 */
|
||||||
func insertionSort(nums: inout [Int]) {
|
func insertionSort(nums: inout [Int]) {
|
||||||
// 外循环:已排序区间为 [0, i-1]
|
// 外循环:已排序区间为 [0, i-1]
|
||||||
for i in stride(from: 1, to: nums.count, by: 1) {
|
for i in nums.indices.dropFirst() {
|
||||||
let base = nums[i]
|
let base = nums[i]
|
||||||
var j = i - 1
|
var j = i - 1
|
||||||
// 内循环:将 base 插入到已排序区间 [0, i-1] 中的正确位置
|
// 内循环:将 base 插入到已排序区间 [0, i-1] 中的正确位置
|
||||||
|
@ -16,12 +16,11 @@ func merge(nums: inout [Int], left: Int, mid: Int, right: Int) {
|
|||||||
if nums[i] <= nums[j] {
|
if nums[i] <= nums[j] {
|
||||||
tmp[k] = nums[i]
|
tmp[k] = nums[i]
|
||||||
i += 1
|
i += 1
|
||||||
k += 1
|
|
||||||
} else {
|
} else {
|
||||||
tmp[k] = nums[j]
|
tmp[k] = nums[j]
|
||||||
j += 1
|
j += 1
|
||||||
k += 1
|
|
||||||
}
|
}
|
||||||
|
k += 1
|
||||||
}
|
}
|
||||||
// 将左子数组和右子数组的剩余元素复制到临时数组中
|
// 将左子数组和右子数组的剩余元素复制到临时数组中
|
||||||
while i <= mid {
|
while i <= mid {
|
||||||
@ -60,7 +59,7 @@ enum MergeSort {
|
|||||||
static func main() {
|
static func main() {
|
||||||
/* 归并排序 */
|
/* 归并排序 */
|
||||||
var nums = [7, 3, 2, 6, 0, 1, 5, 4]
|
var nums = [7, 3, 2, 6, 0, 1, 5, 4]
|
||||||
mergeSort(nums: &nums, left: 0, right: nums.count - 1)
|
mergeSort(nums: &nums, left: nums.startIndex, right: nums.endIndex - 1)
|
||||||
print("归并排序完成后 nums = \(nums)")
|
print("归并排序完成后 nums = \(nums)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,6 @@
|
|||||||
* Author: nuomi1 (nuomi1@qq.com)
|
* Author: nuomi1 (nuomi1@qq.com)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* 元素交换 */
|
|
||||||
func swap(nums: inout [Int], i: Int, j: Int) {
|
|
||||||
let tmp = nums[i]
|
|
||||||
nums[i] = nums[j]
|
|
||||||
nums[j] = tmp
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 快速排序类 */
|
/* 快速排序类 */
|
||||||
/* 哨兵划分 */
|
/* 哨兵划分 */
|
||||||
func partition(nums: inout [Int], left: Int, right: Int) -> Int {
|
func partition(nums: inout [Int], left: Int, right: Int) -> Int {
|
||||||
@ -24,9 +17,9 @@ func partition(nums: inout [Int], left: Int, right: Int) -> Int {
|
|||||||
while i < j, nums[i] <= nums[left] {
|
while i < j, nums[i] <= nums[left] {
|
||||||
i += 1 // 从左向右找首个大于基准数的元素
|
i += 1 // 从左向右找首个大于基准数的元素
|
||||||
}
|
}
|
||||||
swap(nums: &nums, i: i, j: j) // 交换这两个元素
|
nums.swapAt(i, j) // 交换这两个元素
|
||||||
}
|
}
|
||||||
swap(nums: &nums, i: i, j: left) // 将基准数交换至两子数组的分界线
|
nums.swapAt(i, left) // 将基准数交换至两子数组的分界线
|
||||||
return i // 返回基准数的索引
|
return i // 返回基准数的索引
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +36,6 @@ func quickSort(nums: inout [Int], left: Int, right: Int) {
|
|||||||
quickSort(nums: &nums, left: pivot + 1, right: right)
|
quickSort(nums: &nums, left: pivot + 1, right: right)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* 快速排序类(中位基准数优化) */
|
/* 快速排序类(中位基准数优化) */
|
||||||
/* 选取三个候选元素的中位数 */
|
/* 选取三个候选元素的中位数 */
|
||||||
func medianThree(nums: [Int], left: Int, mid: Int, right: Int) -> Int {
|
func medianThree(nums: [Int], left: Int, mid: Int, right: Int) -> Int {
|
||||||
@ -51,12 +43,12 @@ func medianThree(nums: [Int], left: Int, mid: Int, right: Int) -> Int {
|
|||||||
let m = nums[mid]
|
let m = nums[mid]
|
||||||
let r = nums[right]
|
let r = nums[right]
|
||||||
if (l <= m && m <= r) || (r <= m && m <= l) {
|
if (l <= m && m <= r) || (r <= m && m <= l) {
|
||||||
return mid; // m 在 l 和 r 之间
|
return mid // m 在 l 和 r 之间
|
||||||
}
|
}
|
||||||
if (m <= l && l <= r) || (r <= l && l <= m) {
|
if (m <= l && l <= r) || (r <= l && l <= m) {
|
||||||
return left; // l 在 m 和 r 之间
|
return left // l 在 m 和 r 之间
|
||||||
}
|
}
|
||||||
return right;
|
return right
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 哨兵划分(三数取中值) */
|
/* 哨兵划分(三数取中值) */
|
||||||
@ -64,7 +56,7 @@ func partitionMedian(nums: inout [Int], left: Int, right: Int) -> Int {
|
|||||||
// 选取三个候选元素的中位数
|
// 选取三个候选元素的中位数
|
||||||
let med = medianThree(nums: nums, left: left, mid: (left + right) / 2, right: right)
|
let med = medianThree(nums: nums, left: left, mid: (left + right) / 2, right: right)
|
||||||
// 将中位数交换至数组最左端
|
// 将中位数交换至数组最左端
|
||||||
swap(nums: &nums, i: left, j: med)
|
nums.swapAt(left, med)
|
||||||
return partition(nums: &nums, left: left, right: right)
|
return partition(nums: &nums, left: left, right: right)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +73,6 @@ func quickSortMedian(nums: inout [Int], left: Int, right: Int) {
|
|||||||
quickSortMedian(nums: &nums, left: pivot + 1, right: right)
|
quickSortMedian(nums: &nums, left: pivot + 1, right: right)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* 快速排序(尾递归优化) */
|
/* 快速排序(尾递归优化) */
|
||||||
func quickSortTailCall(nums: inout [Int], left: Int, right: Int) {
|
func quickSortTailCall(nums: inout [Int], left: Int, right: Int) {
|
||||||
var left = left
|
var left = left
|
||||||
@ -107,17 +98,17 @@ enum QuickSort {
|
|||||||
static func main() {
|
static func main() {
|
||||||
/* 快速排序 */
|
/* 快速排序 */
|
||||||
var nums = [2, 4, 1, 0, 3, 5]
|
var nums = [2, 4, 1, 0, 3, 5]
|
||||||
quickSort(nums: &nums, left: 0, right: nums.count - 1)
|
quickSort(nums: &nums, left: nums.startIndex, right: nums.endIndex - 1)
|
||||||
print("快速排序完成后 nums = \(nums)")
|
print("快速排序完成后 nums = \(nums)")
|
||||||
|
|
||||||
/* 快速排序(中位基准数优化) */
|
/* 快速排序(中位基准数优化) */
|
||||||
var nums1 = [2, 4, 1, 0, 3, 5]
|
var nums1 = [2, 4, 1, 0, 3, 5]
|
||||||
quickSortMedian(nums: &nums1, left: 0, right: nums1.count - 1)
|
quickSortMedian(nums: &nums1, left: nums1.startIndex, right: nums1.endIndex - 1)
|
||||||
print("快速排序(中位基准数优化)完成后 nums1 = \(nums1)")
|
print("快速排序(中位基准数优化)完成后 nums1 = \(nums1)")
|
||||||
|
|
||||||
/* 快速排序(尾递归优化) */
|
/* 快速排序(尾递归优化) */
|
||||||
var nums2 = [2, 4, 1, 0, 3, 5]
|
var nums2 = [2, 4, 1, 0, 3, 5]
|
||||||
quickSortTailCall(nums: &nums2, left: 0, right: nums2.count - 1)
|
quickSortTailCall(nums: &nums2, left: nums2.startIndex, right: nums2.endIndex - 1)
|
||||||
print("快速排序(尾递归优化)完成后 nums2 = \(nums2)")
|
print("快速排序(尾递归优化)完成后 nums2 = \(nums2)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,6 @@ func digit(num: Int, exp: Int) -> Int {
|
|||||||
func countingSortDigit(nums: inout [Int], exp: Int) {
|
func countingSortDigit(nums: inout [Int], exp: Int) {
|
||||||
// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶数组
|
// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶数组
|
||||||
var counter = Array(repeating: 0, count: 10)
|
var counter = Array(repeating: 0, count: 10)
|
||||||
let n = nums.count
|
|
||||||
// 统计 0~9 各数字的出现次数
|
// 统计 0~9 各数字的出现次数
|
||||||
for i in nums.indices {
|
for i in nums.indices {
|
||||||
let d = digit(num: nums[i], exp: exp) // 获取 nums[i] 第 k 位,记为 d
|
let d = digit(num: nums[i], exp: exp) // 获取 nums[i] 第 k 位,记为 d
|
||||||
@ -25,8 +24,8 @@ func countingSortDigit(nums: inout [Int], exp: Int) {
|
|||||||
counter[i] += counter[i - 1]
|
counter[i] += counter[i - 1]
|
||||||
}
|
}
|
||||||
// 倒序遍历,根据桶内统计结果,将各元素填入 res
|
// 倒序遍历,根据桶内统计结果,将各元素填入 res
|
||||||
var res = Array(repeating: 0, count: n)
|
var res = Array(repeating: 0, count: nums.count)
|
||||||
for i in stride(from: n - 1, through: 0, by: -1) {
|
for i in nums.indices.reversed() {
|
||||||
let d = digit(num: nums[i], exp: exp)
|
let d = digit(num: nums[i], exp: exp)
|
||||||
let j = counter[d] - 1 // 获取 d 在数组中的索引 j
|
let j = counter[d] - 1 // 获取 d 在数组中的索引 j
|
||||||
res[j] = nums[i] // 将当前元素填入索引 j
|
res[j] = nums[i] // 将当前元素填入索引 j
|
||||||
@ -62,8 +61,18 @@ enum RadixSort {
|
|||||||
/* Driver Code */
|
/* Driver Code */
|
||||||
static func main() {
|
static func main() {
|
||||||
// 基数排序
|
// 基数排序
|
||||||
var nums = [10546151, 35663510, 42865989, 34862445, 81883077,
|
var nums = [
|
||||||
88906420, 72429244, 30524779, 82060337, 63832996]
|
10_546_151,
|
||||||
|
35_663_510,
|
||||||
|
42_865_989,
|
||||||
|
34_862_445,
|
||||||
|
81_883_077,
|
||||||
|
88_906_420,
|
||||||
|
72_429_244,
|
||||||
|
30_524_779,
|
||||||
|
82_060_337,
|
||||||
|
63_832_996,
|
||||||
|
]
|
||||||
radixSort(nums: &nums)
|
radixSort(nums: &nums)
|
||||||
print("基数排序完成后 nums = \(nums)")
|
print("基数排序完成后 nums = \(nums)")
|
||||||
}
|
}
|
||||||
|
@ -8,13 +8,13 @@
|
|||||||
class ArrayDeque {
|
class ArrayDeque {
|
||||||
private var nums: [Int] // 用于存储双向队列元素的数组
|
private var nums: [Int] // 用于存储双向队列元素的数组
|
||||||
private var front: Int // 队首指针,指向队首元素
|
private var front: Int // 队首指针,指向队首元素
|
||||||
private var queSize: Int // 双向队列长度
|
private var _size: Int // 双向队列长度
|
||||||
|
|
||||||
/* 构造方法 */
|
/* 构造方法 */
|
||||||
init(capacity: Int) {
|
init(capacity: Int) {
|
||||||
nums = Array(repeating: 0, count: capacity)
|
nums = Array(repeating: 0, count: capacity)
|
||||||
front = 0
|
front = 0
|
||||||
queSize = 0
|
_size = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 获取双向队列的容量 */
|
/* 获取双向队列的容量 */
|
||||||
@ -24,7 +24,7 @@ class ArrayDeque {
|
|||||||
|
|
||||||
/* 获取双向队列的长度 */
|
/* 获取双向队列的长度 */
|
||||||
func size() -> Int {
|
func size() -> Int {
|
||||||
queSize
|
_size
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 判断双向队列是否为空 */
|
/* 判断双向队列是否为空 */
|
||||||
@ -51,7 +51,7 @@ class ArrayDeque {
|
|||||||
front = index(i: front - 1)
|
front = index(i: front - 1)
|
||||||
// 将 num 添加至队首
|
// 将 num 添加至队首
|
||||||
nums[front] = num
|
nums[front] = num
|
||||||
queSize += 1
|
_size += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 队尾入队 */
|
/* 队尾入队 */
|
||||||
@ -64,7 +64,7 @@ class ArrayDeque {
|
|||||||
let rear = index(i: front + size())
|
let rear = index(i: front + size())
|
||||||
// 将 num 添加至队尾
|
// 将 num 添加至队尾
|
||||||
nums[rear] = num
|
nums[rear] = num
|
||||||
queSize += 1
|
_size += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 队首出队 */
|
/* 队首出队 */
|
||||||
@ -72,14 +72,14 @@ class ArrayDeque {
|
|||||||
let num = peekFirst()
|
let num = peekFirst()
|
||||||
// 队首指针向后移动一位
|
// 队首指针向后移动一位
|
||||||
front = index(i: front + 1)
|
front = index(i: front + 1)
|
||||||
queSize -= 1
|
_size -= 1
|
||||||
return num
|
return num
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 队尾出队 */
|
/* 队尾出队 */
|
||||||
func popLast() -> Int {
|
func popLast() -> Int {
|
||||||
let num = peekLast()
|
let num = peekLast()
|
||||||
queSize -= 1
|
_size -= 1
|
||||||
return num
|
return num
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,11 +104,7 @@ class ArrayDeque {
|
|||||||
/* 返回数组用于打印 */
|
/* 返回数组用于打印 */
|
||||||
func toArray() -> [Int] {
|
func toArray() -> [Int] {
|
||||||
// 仅转换有效长度范围内的列表元素
|
// 仅转换有效长度范围内的列表元素
|
||||||
var res = Array(repeating: 0, count: size())
|
(front ..< front + size()).map { nums[index(i: $0)] }
|
||||||
for (i, j) in sequence(first: (0, front), next: { $0 < self.size() - 1 ? ($0 + 1, $1 + 1) : nil }) {
|
|
||||||
res[i] = nums[index(i: j)]
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,12 +7,14 @@
|
|||||||
/* 基于环形数组实现的队列 */
|
/* 基于环形数组实现的队列 */
|
||||||
class ArrayQueue {
|
class ArrayQueue {
|
||||||
private var nums: [Int] // 用于存储队列元素的数组
|
private var nums: [Int] // 用于存储队列元素的数组
|
||||||
private var front = 0 // 队首指针,指向队首元素
|
private var front: Int // 队首指针,指向队首元素
|
||||||
private var queSize = 0 // 队列长度
|
private var _size: Int // 队列长度
|
||||||
|
|
||||||
init(capacity: Int) {
|
init(capacity: Int) {
|
||||||
// 初始化数组
|
// 初始化数组
|
||||||
nums = Array(repeating: 0, count: capacity)
|
nums = Array(repeating: 0, count: capacity)
|
||||||
|
front = 0
|
||||||
|
_size = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 获取队列的容量 */
|
/* 获取队列的容量 */
|
||||||
@ -22,12 +24,12 @@ class ArrayQueue {
|
|||||||
|
|
||||||
/* 获取队列的长度 */
|
/* 获取队列的长度 */
|
||||||
func size() -> Int {
|
func size() -> Int {
|
||||||
queSize
|
_size
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 判断队列是否为空 */
|
/* 判断队列是否为空 */
|
||||||
func isEmpty() -> Bool {
|
func isEmpty() -> Bool {
|
||||||
queSize == 0
|
size() == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 入队 */
|
/* 入队 */
|
||||||
@ -38,10 +40,10 @@ class ArrayQueue {
|
|||||||
}
|
}
|
||||||
// 计算队尾指针,指向队尾索引 + 1
|
// 计算队尾指针,指向队尾索引 + 1
|
||||||
// 通过取余操作实现 rear 越过数组尾部后回到头部
|
// 通过取余操作实现 rear 越过数组尾部后回到头部
|
||||||
let rear = (front + queSize) % capacity()
|
let rear = (front + size()) % capacity()
|
||||||
// 将 num 添加至队尾
|
// 将 num 添加至队尾
|
||||||
nums[rear] = num
|
nums[rear] = num
|
||||||
queSize += 1
|
_size += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 出队 */
|
/* 出队 */
|
||||||
@ -50,7 +52,7 @@ class ArrayQueue {
|
|||||||
let num = peek()
|
let num = peek()
|
||||||
// 队首指针向后移动一位,若越过尾部,则返回到数组头部
|
// 队首指针向后移动一位,若越过尾部,则返回到数组头部
|
||||||
front = (front + 1) % capacity()
|
front = (front + 1) % capacity()
|
||||||
queSize -= 1
|
_size -= 1
|
||||||
return num
|
return num
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,11 +67,7 @@ class ArrayQueue {
|
|||||||
/* 返回数组 */
|
/* 返回数组 */
|
||||||
func toArray() -> [Int] {
|
func toArray() -> [Int] {
|
||||||
// 仅转换有效长度范围内的列表元素
|
// 仅转换有效长度范围内的列表元素
|
||||||
var res = Array(repeating: 0, count: queSize)
|
(front ..< front + size()).map { nums[$0 % capacity()] }
|
||||||
for (i, j) in sequence(first: (0, front), next: { $0 < self.queSize - 1 ? ($0 + 1, $1 + 1) : nil }) {
|
|
||||||
res[i] = nums[j % capacity()]
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,15 +19,15 @@ class ListNode {
|
|||||||
class LinkedListDeque {
|
class LinkedListDeque {
|
||||||
private var front: ListNode? // 头节点 front
|
private var front: ListNode? // 头节点 front
|
||||||
private var rear: ListNode? // 尾节点 rear
|
private var rear: ListNode? // 尾节点 rear
|
||||||
private var queSize: Int // 双向队列的长度
|
private var _size: Int // 双向队列的长度
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
queSize = 0
|
_size = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 获取双向队列的长度 */
|
/* 获取双向队列的长度 */
|
||||||
func size() -> Int {
|
func size() -> Int {
|
||||||
queSize
|
_size
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 判断双向队列是否为空 */
|
/* 判断双向队列是否为空 */
|
||||||
@ -57,7 +57,7 @@ class LinkedListDeque {
|
|||||||
node.prev = rear
|
node.prev = rear
|
||||||
rear = node // 更新尾节点
|
rear = node // 更新尾节点
|
||||||
}
|
}
|
||||||
queSize += 1 // 更新队列长度
|
_size += 1 // 更新队列长度
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 队首入队 */
|
/* 队首入队 */
|
||||||
@ -98,7 +98,7 @@ class LinkedListDeque {
|
|||||||
}
|
}
|
||||||
rear = rPrev // 更新尾节点
|
rear = rPrev // 更新尾节点
|
||||||
}
|
}
|
||||||
queSize -= 1 // 更新队列长度
|
_size -= 1 // 更新队列长度
|
||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,13 +113,19 @@ class LinkedListDeque {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 访问队首元素 */
|
/* 访问队首元素 */
|
||||||
func peekFirst() -> Int? {
|
func peekFirst() -> Int {
|
||||||
isEmpty() ? nil : front?.val
|
if isEmpty() {
|
||||||
|
fatalError("双向队列为空")
|
||||||
|
}
|
||||||
|
return front!.val
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 访问队尾元素 */
|
/* 访问队尾元素 */
|
||||||
func peekLast() -> Int? {
|
func peekLast() -> Int {
|
||||||
isEmpty() ? nil : rear?.val
|
if isEmpty() {
|
||||||
|
fatalError("双向队列为空")
|
||||||
|
}
|
||||||
|
return rear!.val
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 返回数组用于打印 */
|
/* 返回数组用于打印 */
|
||||||
@ -147,9 +153,9 @@ enum _LinkedListDeque {
|
|||||||
|
|
||||||
/* 访问元素 */
|
/* 访问元素 */
|
||||||
let peekFirst = deque.peekFirst()
|
let peekFirst = deque.peekFirst()
|
||||||
print("队首元素 peekFirst = \(peekFirst!)")
|
print("队首元素 peekFirst = \(peekFirst)")
|
||||||
let peekLast = deque.peekLast()
|
let peekLast = deque.peekLast()
|
||||||
print("队尾元素 peekLast = \(peekLast!)")
|
print("队尾元素 peekLast = \(peekLast)")
|
||||||
|
|
||||||
/* 元素入队 */
|
/* 元素入队 */
|
||||||
deque.pushLast(num: 4)
|
deque.pushLast(num: 4)
|
||||||
|
@ -10,9 +10,11 @@ import utils
|
|||||||
class LinkedListQueue {
|
class LinkedListQueue {
|
||||||
private var front: ListNode? // 头节点
|
private var front: ListNode? // 头节点
|
||||||
private var rear: ListNode? // 尾节点
|
private var rear: ListNode? // 尾节点
|
||||||
private var _size = 0
|
private var _size: Int
|
||||||
|
|
||||||
init() {}
|
init() {
|
||||||
|
_size = 0
|
||||||
|
}
|
||||||
|
|
||||||
/* 获取队列的长度 */
|
/* 获取队列的长度 */
|
||||||
func size() -> Int {
|
func size() -> Int {
|
||||||
|
@ -9,9 +9,11 @@ import utils
|
|||||||
/* 基于链表实现的栈 */
|
/* 基于链表实现的栈 */
|
||||||
class LinkedListStack {
|
class LinkedListStack {
|
||||||
private var _peek: ListNode? // 将头节点作为栈顶
|
private var _peek: ListNode? // 将头节点作为栈顶
|
||||||
private var _size = 0 // 栈的长度
|
private var _size: Int // 栈的长度
|
||||||
|
|
||||||
init() {}
|
init() {
|
||||||
|
_size = 0
|
||||||
|
}
|
||||||
|
|
||||||
/* 获取栈的长度 */
|
/* 获取栈的长度 */
|
||||||
func size() -> Int {
|
func size() -> Int {
|
||||||
@ -51,8 +53,8 @@ class LinkedListStack {
|
|||||||
/* 将 List 转化为 Array 并返回 */
|
/* 将 List 转化为 Array 并返回 */
|
||||||
func toArray() -> [Int] {
|
func toArray() -> [Int] {
|
||||||
var node = _peek
|
var node = _peek
|
||||||
var res = Array(repeating: 0, count: _size)
|
var res = Array(repeating: 0, count: size())
|
||||||
for i in sequence(first: res.count - 1, next: { $0 >= 0 + 1 ? $0 - 1 : nil }) {
|
for i in res.indices.reversed() {
|
||||||
res[i] = node!.val
|
res[i] = node!.val
|
||||||
node = node?.next
|
node = node?.next
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ class ArrayBinaryTree {
|
|||||||
func levelOrder() -> [Int] {
|
func levelOrder() -> [Int] {
|
||||||
var res: [Int] = []
|
var res: [Int] = []
|
||||||
// 直接遍历数组
|
// 直接遍历数组
|
||||||
for i in stride(from: 0, to: size(), by: 1) {
|
for i in 0 ..< size() {
|
||||||
if let val = val(i: i) {
|
if let val = val(i: i) {
|
||||||
res.append(val)
|
res.append(val)
|
||||||
}
|
}
|
||||||
|
@ -10,10 +10,12 @@ import utils
|
|||||||
class AVLTree {
|
class AVLTree {
|
||||||
fileprivate var root: TreeNode? // 根节点
|
fileprivate var root: TreeNode? // 根节点
|
||||||
|
|
||||||
|
init() {}
|
||||||
|
|
||||||
/* 获取节点高度 */
|
/* 获取节点高度 */
|
||||||
func height(node: TreeNode?) -> Int {
|
func height(node: TreeNode?) -> Int {
|
||||||
// 空节点高度为 -1 ,叶节点高度为 0
|
// 空节点高度为 -1 ,叶节点高度为 0
|
||||||
node == nil ? -1 : node!.height
|
node?.height ?? -1
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 更新节点高度 */
|
/* 更新节点高度 */
|
||||||
@ -132,7 +134,7 @@ class AVLTree {
|
|||||||
node?.right = removeHelper(node: node?.right, val: val)
|
node?.right = removeHelper(node: node?.right, val: val)
|
||||||
} else {
|
} else {
|
||||||
if node?.left == nil || node?.right == nil {
|
if node?.left == nil || node?.right == nil {
|
||||||
let child = node?.left != nil ? node?.left : node?.right
|
let child = node?.left ?? node?.right
|
||||||
// 子节点数量 = 0 ,直接删除 node 并返回
|
// 子节点数量 = 0 ,直接删除 node 并返回
|
||||||
if child == nil {
|
if child == nil {
|
||||||
return nil
|
return nil
|
||||||
|
@ -108,7 +108,7 @@ class BinarySearchTree {
|
|||||||
// 子节点数量 = 0 or 1
|
// 子节点数量 = 0 or 1
|
||||||
if cur?.left == nil || cur?.right == nil {
|
if cur?.left == nil || cur?.right == nil {
|
||||||
// 当子节点数量 = 0 / 1 时, child = null / 该子节点
|
// 当子节点数量 = 0 / 1 时, child = null / 该子节点
|
||||||
let child = cur?.left != nil ? cur?.left : cur?.right
|
let child = cur?.left ?? cur?.right
|
||||||
// 删除节点 cur
|
// 删除节点 cur
|
||||||
if cur !== root {
|
if cur !== root {
|
||||||
if pre?.left === cur {
|
if pre?.left === cur {
|
||||||
|
@ -22,19 +22,11 @@ public class Vertex: Hashable {
|
|||||||
|
|
||||||
/* 输入值列表 vals ,返回顶点列表 vets */
|
/* 输入值列表 vals ,返回顶点列表 vets */
|
||||||
public static func valsToVets(vals: [Int]) -> [Vertex] {
|
public static func valsToVets(vals: [Int]) -> [Vertex] {
|
||||||
var vets: [Vertex] = []
|
vals.map { Vertex(val: $0) }
|
||||||
for val in vals {
|
|
||||||
vets.append(Vertex(val: val))
|
|
||||||
}
|
|
||||||
return vets
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 输入顶点列表 vets ,返回值列表 vals */
|
/* 输入顶点列表 vets ,返回值列表 vals */
|
||||||
public static func vetsToVals(vets: [Vertex]) -> [Int] {
|
public static func vetsToVals(vets: [Vertex]) -> [Int] {
|
||||||
var vals: [Int] = []
|
vets.map { $0.val }
|
||||||
for vet in vets {
|
|
||||||
vals.append(vet.val)
|
|
||||||
}
|
|
||||||
return vals
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -317,7 +317,7 @@ Let's understand this concept of "time growth trend" with an example. Assume the
|
|||||||
|
|
||||||
// Time complexity of algorithm C: constant order
|
// Time complexity of algorithm C: constant order
|
||||||
func algorithmC(n: Int) {
|
func algorithmC(n: Int) {
|
||||||
for _ in 0 ..< 1000000 {
|
for _ in 0 ..< 1_000_000 {
|
||||||
print(0)
|
print(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,10 +101,10 @@ In other words, **basic data types provide the "content type" of data, while dat
|
|||||||
|
|
||||||
```swift title=""
|
```swift title=""
|
||||||
// Using various basic data types to initialize arrays
|
// Using various basic data types to initialize arrays
|
||||||
let numbers = Array(repeating: Int(), count: 5)
|
let numbers = Array(repeating: 0, count: 5)
|
||||||
let decimals = Array(repeating: Double(), count: 5)
|
let decimals = Array(repeating: 0.0, count: 5)
|
||||||
let characters = Array(repeating: Character("a"), count: 5)
|
let characters: [Character] = Array(repeating: "a", count: 5)
|
||||||
let bools = Array(repeating: Bool(), count: 5)
|
let bools = Array(repeating: false, count: 5)
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "JS"
|
=== "JS"
|
||||||
|
@ -317,7 +317,7 @@ $$
|
|||||||
|
|
||||||
// 算法 C 的时间复杂度:常数阶
|
// 算法 C 的时间复杂度:常数阶
|
||||||
func algorithmC(n: Int) {
|
func algorithmC(n: Int) {
|
||||||
for _ in 0 ..< 1000000 {
|
for _ in 0 ..< 1_000_000 {
|
||||||
print(0)
|
print(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,10 +101,10 @@
|
|||||||
|
|
||||||
```swift title=""
|
```swift title=""
|
||||||
// 使用多种基本数据类型来初始化数组
|
// 使用多种基本数据类型来初始化数组
|
||||||
let numbers = Array(repeating: Int(), count: 5)
|
let numbers = Array(repeating: 0, count: 5)
|
||||||
let decimals = Array(repeating: Double(), count: 5)
|
let decimals = Array(repeating: 0.0, count: 5)
|
||||||
let characters = Array(repeating: Character("a"), count: 5)
|
let characters: [Character] = Array(repeating: "a", count: 5)
|
||||||
let bools = Array(repeating: Bool(), count: 5)
|
let bools = Array(repeating: false, count: 5)
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "JS"
|
=== "JS"
|
||||||
|
@ -270,7 +270,35 @@
|
|||||||
=== "Swift"
|
=== "Swift"
|
||||||
|
|
||||||
```swift title="heap.swift"
|
```swift title="heap.swift"
|
||||||
// Swift 未提供内置 Heap 类
|
/* 初始化堆 */
|
||||||
|
// Swift 的 Heap 类型同时支持最大堆和最小堆,且需要引入 swift-collections
|
||||||
|
var heap = Heap<Int>()
|
||||||
|
|
||||||
|
/* 元素入堆 */
|
||||||
|
heap.insert(1)
|
||||||
|
heap.insert(3)
|
||||||
|
heap.insert(2)
|
||||||
|
heap.insert(5)
|
||||||
|
heap.insert(4)
|
||||||
|
|
||||||
|
/* 获取堆顶元素 */
|
||||||
|
var peek = heap.max()!
|
||||||
|
|
||||||
|
/* 堆顶元素出堆 */
|
||||||
|
peek = heap.removeMax() // 5
|
||||||
|
peek = heap.removeMax() // 4
|
||||||
|
peek = heap.removeMax() // 3
|
||||||
|
peek = heap.removeMax() // 2
|
||||||
|
peek = heap.removeMax() // 1
|
||||||
|
|
||||||
|
/* 获取堆大小 */
|
||||||
|
let size = heap.count
|
||||||
|
|
||||||
|
/* 判断堆是否为空 */
|
||||||
|
let isEmpty = heap.isEmpty
|
||||||
|
|
||||||
|
/* 输入列表并建堆 */
|
||||||
|
let heap2 = Heap([1, 3, 2, 5, 4])
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "JS"
|
=== "JS"
|
||||||
|
Loading…
Reference in New Issue
Block a user