forked from krahets/hello-algo
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(kotlin): add kotlin codes for the chapter of searching. (krahets…
- Loading branch information
Showing
6 changed files
with
321 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
/** | ||
* File: binary_search.kt | ||
* Created Time: 2024-1-25 | ||
* Author: curtishd ([email protected]) | ||
*/ | ||
|
||
package chapter_searching | ||
|
||
/* 二分查找(双闭区间) */ | ||
fun binarySearch(nums: IntArray, target: Int): Int { | ||
// 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素 | ||
var i = 0 | ||
var j = nums.size - 1 | ||
// 循环,当搜索区间为空时跳出(当 i > j 时为空) | ||
while (i <= j) { | ||
val m = i + (j - i) / 2 // 计算中点索引 m | ||
if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j] 中 | ||
i = m + 1 | ||
else if (nums[m] > target) // 此情况说明 target 在区间 [i, m-1] 中 | ||
j = m - 1 | ||
else // 找到目标元素,返回其索引 | ||
return m | ||
} | ||
// 未找到目标元素,返回 -1 | ||
return -1 | ||
} | ||
|
||
/* 二分查找(左闭右开区间) */ | ||
fun binarySearchLCRO(nums: IntArray, target: Int): Int { | ||
// 初始化左闭右开区间 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1 | ||
var i = 0 | ||
var j = nums.size | ||
// 循环,当搜索区间为空时跳出(当 i = j 时为空) | ||
while (i < j) { | ||
val m = i + (j - i) / 2 // 计算中点索引 m | ||
if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j) 中 | ||
i = m + 1 | ||
else if (nums[m] > target) // 此情况说明 target 在区间 [i, m) 中 | ||
j = m | ||
else // 找到目标元素,返回其索引 | ||
return m | ||
} | ||
// 未找到目标元素,返回 -1 | ||
return -1 | ||
} | ||
|
||
/* Driver Code */ | ||
fun main() { | ||
val target = 6 | ||
val nums = intArrayOf(1, 3, 6, 8, 12, 15, 23, 26, 31, 35) | ||
|
||
/* 二分查找(双闭区间) */ | ||
var index = binarySearch(nums, target) | ||
println("目标元素 6 的索引 = $index") | ||
|
||
/* 二分查找(左闭右开区间) */ | ||
index = binarySearchLCRO(nums, target) | ||
println("目标元素 6 的索引 = $index") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/** | ||
* File: binary_search_edge.kt | ||
* Created Time: 2024-1-25 | ||
* Author: curtishd ([email protected]) | ||
*/ | ||
|
||
package chapter_searching | ||
|
||
/* 二分查找最左一个 target */ | ||
fun binarySearchLeftEdge(nums: IntArray, target: Int): Int { | ||
// 等价于查找 target 的插入点 | ||
val i = binarySearchInsertion(nums, target) | ||
// 未找到 target ,返回 -1 | ||
if (i == nums.size || nums[i] != target) { | ||
return -1 | ||
} | ||
// 找到 target ,返回索引 i | ||
return i | ||
} | ||
|
||
/* 二分查找最右一个 target */ | ||
fun binarySearchRightEdge(nums: IntArray, target: Int): Int { | ||
// 转化为查找最左一个 target + 1 | ||
val i = binarySearchInsertion(nums, target + 1) | ||
// j 指向最右一个 target ,i 指向首个大于 target 的元素 | ||
val j = i - 1 | ||
// 未找到 target ,返回 -1 | ||
if (j == -1 || nums[j] != target) { | ||
return -1 | ||
} | ||
// 找到 target ,返回索引 j | ||
return j | ||
} | ||
|
||
/* Driver Code */ | ||
fun main() { | ||
// 包含重复元素的数组 | ||
val nums = intArrayOf(1, 3, 6, 6, 6, 6, 6, 10, 12, 15) | ||
println("\n数组 nums = ${nums.contentToString()}") | ||
|
||
// 二分查找左边界和右边界 | ||
for (target in intArrayOf(6, 7)) { | ||
var index = binarySearchLeftEdge(nums, target) | ||
println("最左一个元素 $target 的索引为 $index") | ||
index = binarySearchRightEdge(nums, target) | ||
println("最右一个元素 $target 的索引为 $index") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/** | ||
* File: binary_search_insertion.kt | ||
* Created Time: 2024-1-25 | ||
* Author: curtishd ([email protected]) | ||
*/ | ||
|
||
package chapter_searching | ||
|
||
/* 二分查找插入点(无重复元素) */ | ||
fun binarySearchInsertionSimple(nums: IntArray, target: Int): Int { | ||
var i = 0 | ||
var j = nums.size - 1 // 初始化双闭区间 [0, n-1] | ||
while (i <= j) { | ||
val m = i + (j - i) / 2 // 计算中点索引 m | ||
if (nums[m] < target) { | ||
i = m + 1 // target 在区间 [m+1, j] 中 | ||
} else if (nums[m] > target) { | ||
j = m - 1 // target 在区间 [i, m-1] 中 | ||
} else { | ||
return m // 找到 target ,返回插入点 m | ||
} | ||
} | ||
// 未找到 target ,返回插入点 i | ||
return i | ||
} | ||
|
||
/* 二分查找插入点(存在重复元素) */ | ||
fun binarySearchInsertion(nums: IntArray, target: Int): Int { | ||
var i = 0 | ||
var j = nums.size - 1 // 初始化双闭区间 [0, n-1] | ||
while (i <= j) { | ||
val m = i + (j - i) / 2 // 计算中点索引 m | ||
if (nums[m] < target) { | ||
i = m + 1 // target 在区间 [m+1, j] 中 | ||
} else if (nums[m] > target) { | ||
j = m - 1 // target 在区间 [i, m-1] 中 | ||
} else { | ||
j = m - 1 // 首个小于 target 的元素在区间 [i, m-1] 中 | ||
} | ||
} | ||
// 返回插入点 i | ||
return i | ||
} | ||
|
||
/* Driver Code */ | ||
fun main() { | ||
// 无重复元素的数组 | ||
var nums = intArrayOf(1, 3, 6, 8, 12, 15, 23, 26, 31, 35) | ||
println("\n数组 nums = ${nums.contentToString()}") | ||
// 二分查找插入点 | ||
for (target in intArrayOf(6, 9)) { | ||
val index = binarySearchInsertionSimple(nums, target) | ||
println("元素 $target 的插入点的索引为 $index") | ||
} | ||
|
||
// 包含重复元素的数组 | ||
nums = intArrayOf(1, 3, 6, 6, 6, 6, 6, 10, 12, 15) | ||
println("\n数组 nums = ${nums.contentToString()}") | ||
|
||
// 二分查找插入点 | ||
for (target in intArrayOf(2, 6, 20)) { | ||
val index = binarySearchInsertion(nums, target) | ||
println("元素 $target 的插入点的索引为 $index") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/** | ||
* File: hashing_search.kt | ||
* Created Time: 2024-1-25 | ||
* Author: curtishd ([email protected]) | ||
*/ | ||
|
||
package chapter_searching | ||
|
||
import utils.ListNode | ||
import java.util.HashMap | ||
|
||
/* 哈希查找(数组) */ | ||
fun hashingSearchArray(map: Map<Int?, Int>, target: Int): Int { | ||
// 哈希表的 key: 目标元素,value: 索引 | ||
// 若哈希表中无此 key ,返回 -1 | ||
return map.getOrDefault(target, -1) | ||
} | ||
|
||
/* 哈希查找(链表) */ | ||
fun hashingSearchLinkedList(map: Map<Int?, ListNode?>, target: Int): ListNode? { | ||
// 哈希表的 key: 目标节点值,value: 节点对象 | ||
// 若哈希表中无此 key ,返回 null | ||
return map.getOrDefault(target, null) | ||
} | ||
|
||
/* Driver Code */ | ||
fun main() { | ||
val target = 3 | ||
|
||
/* 哈希查找(数组) */ | ||
val nums = intArrayOf(1, 5, 3, 2, 4, 7, 5, 9, 10, 8) | ||
// 初始化哈希表 | ||
val map = HashMap<Int?, Int>() | ||
for (i in nums.indices) { | ||
map[nums[i]] = i // key: 元素,value: 索引 | ||
} | ||
val index = hashingSearchArray(map, target) | ||
println("目标元素 3 的索引 = $index") | ||
|
||
/* 哈希查找(链表) */ | ||
var head = ListNode.arrToLinkedList(nums) | ||
// 初始化哈希表 | ||
val map1 = HashMap<Int?, ListNode?>() | ||
while (head != null) { | ||
map1[head.value] = head // key: 节点值,value: 节点 | ||
head = head.next | ||
} | ||
val node = hashingSearchLinkedList(map1, target) | ||
println("目标节点值 3 的对应节点对象为 $node") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/** | ||
* File: linear_search.kt | ||
* Created Time: 2024-1-25 | ||
* Author: curtishd ([email protected]) | ||
*/ | ||
|
||
package chapter_searching | ||
|
||
import utils.ListNode | ||
|
||
/* 线性查找(数组) */ | ||
fun linearSearchArray(nums: IntArray, target: Int): Int { | ||
// 遍历数组 | ||
for (i in nums.indices) { | ||
// 找到目标元素,返回其索引 | ||
if (nums[i] == target) | ||
return i | ||
} | ||
// 未找到目标元素,返回 -1 | ||
return -1 | ||
} | ||
|
||
/* 线性查找(链表) */ | ||
fun linearSearchLinkedList(h: ListNode?, target: Int): ListNode? { | ||
// 遍历链表 | ||
var head = h | ||
while (head != null) { | ||
// 找到目标节点,返回之 | ||
if (head.value == target) | ||
return head | ||
head = head.next | ||
} | ||
// 未找到目标节点,返回 null | ||
return null | ||
} | ||
|
||
/* Driver Code */ | ||
fun main() { | ||
val target = 3 | ||
|
||
/* 在数组中执行线性查找 */ | ||
val nums = intArrayOf(1, 5, 3, 2, 4, 7, 5, 9, 10, 8) | ||
val index = linearSearchArray(nums, target) | ||
println("目标元素 3 的索引 = $index") | ||
|
||
/* 在链表中执行线性查找 */ | ||
val head = ListNode.arrToLinkedList(nums) | ||
val node = linearSearchLinkedList(head, target) | ||
println("目标节点值 3 的对应节点对象为 $node") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
/** | ||
* File: two_sum.kt | ||
* Created Time: 2024-1-25 | ||
* Author: curtishd ([email protected]) | ||
*/ | ||
|
||
package chapter_searching | ||
|
||
/* 方法一:暴力枚举 */ | ||
fun twoSumBruteForce(nums: IntArray, target: Int): IntArray { | ||
val size = nums.size | ||
// 两层循环,时间复杂度为 O(n^2) | ||
for (i in 0..<size - 1) { | ||
for (j in i + 1..<size) { | ||
if (nums[i] + nums[j] == target) return intArrayOf(i, j) | ||
} | ||
} | ||
return IntArray(0) | ||
} | ||
|
||
/* 方法二:辅助哈希表 */ | ||
fun twoSumHashTable(nums: IntArray, target: Int): IntArray { | ||
val size = nums.size | ||
// 辅助哈希表,空间复杂度为 O(n) | ||
val dic = HashMap<Int, Int>() | ||
// 单层循环,时间复杂度为 O(n) | ||
for (i in 0..<size) { | ||
if (dic.containsKey(target - nums[i])) { | ||
return intArrayOf(dic[target - nums[i]]!!, i) | ||
} | ||
dic[nums[i]] = i | ||
} | ||
return IntArray(0) | ||
} | ||
|
||
/* Driver Code */ | ||
fun main() { | ||
// ======= Test Case ======= | ||
val nums = intArrayOf(2, 7, 11, 15) | ||
val target = 13 | ||
|
||
// ====== Driver Code ====== | ||
// 方法一 | ||
var res = twoSumBruteForce(nums, target) | ||
println("方法一 res = ${res.contentToString()}") | ||
// 方法二 | ||
res = twoSumHashTable(nums, target) | ||
println("方法二 res = ${res.contentToString()}") | ||
} |