diff --git a/codes/kotlin/chapter_searching/binary_search.kt b/codes/kotlin/chapter_searching/binary_search.kt new file mode 100644 index 000000000..f706240a2 --- /dev/null +++ b/codes/kotlin/chapter_searching/binary_search.kt @@ -0,0 +1,59 @@ +/** + * File: binary_search.kt + * Created Time: 2024-1-25 + * Author: curtishd (1023632660@qq.com) + */ + +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") +} \ No newline at end of file diff --git a/codes/kotlin/chapter_searching/binary_search_edge.kt b/codes/kotlin/chapter_searching/binary_search_edge.kt new file mode 100644 index 000000000..bf4d773cc --- /dev/null +++ b/codes/kotlin/chapter_searching/binary_search_edge.kt @@ -0,0 +1,48 @@ +/** + * File: binary_search_edge.kt + * Created Time: 2024-1-25 + * Author: curtishd (1023632660@qq.com) + */ + +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") + } +} \ No newline at end of file diff --git a/codes/kotlin/chapter_searching/binary_search_insertion.kt b/codes/kotlin/chapter_searching/binary_search_insertion.kt new file mode 100644 index 000000000..74091ce73 --- /dev/null +++ b/codes/kotlin/chapter_searching/binary_search_insertion.kt @@ -0,0 +1,65 @@ +/** + * File: binary_search_insertion.kt + * Created Time: 2024-1-25 + * Author: curtishd (1023632660@qq.com) + */ + +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") + } +} \ No newline at end of file diff --git a/codes/kotlin/chapter_searching/hashing_search.kt b/codes/kotlin/chapter_searching/hashing_search.kt new file mode 100644 index 000000000..fed41f179 --- /dev/null +++ b/codes/kotlin/chapter_searching/hashing_search.kt @@ -0,0 +1,50 @@ +/** + * File: hashing_search.kt + * Created Time: 2024-1-25 + * Author: curtishd (1023632660@qq.com) + */ + +package chapter_searching + +import utils.ListNode +import java.util.HashMap + +/* 哈希查找(数组) */ +fun hashingSearchArray(map: Map, target: Int): Int { + // 哈希表的 key: 目标元素,value: 索引 + // 若哈希表中无此 key ,返回 -1 + return map.getOrDefault(target, -1) +} + +/* 哈希查找(链表) */ +fun hashingSearchLinkedList(map: Map, 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() + 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() + while (head != null) { + map1[head.value] = head // key: 节点值,value: 节点 + head = head.next + } + val node = hashingSearchLinkedList(map1, target) + println("目标节点值 3 的对应节点对象为 $node") +} \ No newline at end of file diff --git a/codes/kotlin/chapter_searching/linear_search.kt b/codes/kotlin/chapter_searching/linear_search.kt new file mode 100644 index 000000000..591468fd1 --- /dev/null +++ b/codes/kotlin/chapter_searching/linear_search.kt @@ -0,0 +1,50 @@ +/** + * File: linear_search.kt + * Created Time: 2024-1-25 + * Author: curtishd (1023632660@qq.com) + */ + +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") +} \ No newline at end of file diff --git a/codes/kotlin/chapter_searching/two_sum.kt b/codes/kotlin/chapter_searching/two_sum.kt new file mode 100644 index 000000000..95b947c08 --- /dev/null +++ b/codes/kotlin/chapter_searching/two_sum.kt @@ -0,0 +1,49 @@ +/** + * File: two_sum.kt + * Created Time: 2024-1-25 + * Author: curtishd (1023632660@qq.com) + */ + +package chapter_searching + +/* 方法一:暴力枚举 */ +fun twoSumBruteForce(nums: IntArray, target: Int): IntArray { + val size = nums.size + // 两层循环,时间复杂度为 O(n^2) + for (i in 0..() + // 单层循环,时间复杂度为 O(n) + for (i in 0..