diff --git a/codes/ruby/chapter_searching/binary_search.rb b/codes/ruby/chapter_searching/binary_search.rb new file mode 100644 index 000000000..7b0738fe1 --- /dev/null +++ b/codes/ruby/chapter_searching/binary_search.rb @@ -0,0 +1,63 @@ +=begin +File: binary_search.rb +Created Time: 2024-04-09 +Author: Blue Bean (lonnnnnnner@gmail.com) +=end + +### 二分查找(双闭区间) ### +def binary_search(nums, target) + # 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素 + i, j = 0, nums.length - 1 + + # 循环,当搜索区间为空时跳出(当 i > j 时为空) + while i <= j + # 理论上 Ruby 的数字可以无限大(取决于内存大小),无须考虑大数越界问题 + m = (i + j) / 2 # 计算中点索引 m + + if nums[m] < target + i = m + 1 # 此情况说明 target 在区间 [m+1, j] 中 + elsif nums[m] > target + j = m - 1 # 此情况说明 target 在区间 [i, m-1] 中 + else + return m # 找到目标元素,返回其索引 + end + end + + -1 # 未找到目标元素,返回 -1 +end + +### 二分查找(左闭右开区间) ### +def binary_search_lcro(nums, target) + # 初始化左闭右开区间 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1 + i, j = 0, nums.length + + # 循环,当搜索区间为空时跳出(当 i = j 时为空) + while i < j + # 计算中点索引 m + m = (i + j) / 2 + + if nums[m] < target + i = m + 1 # 此情况说明 target 在区间 [m+1, j) 中 + elsif nums[m] > target + j = m - 1 # 此情况说明 target 在区间 [i, m) 中 + else + return m # 找到目标元素,返回其索引 + end + end + + -1 # 未找到目标元素,返回 -1 +end + +### Driver Code ### +if __FILE__ == $0 + target = 6 + nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35] + + # 二分查找(双闭区间) + index = binary_search(nums, target) + puts "目标元素 6 的索引 = #{index}" + + # 二分查找(左闭右开区间) + index = binary_search_lcro(nums, target) + puts "目标元素 6 的索引 = #{index}" +end diff --git a/codes/ruby/chapter_searching/binary_search_edge.rb b/codes/ruby/chapter_searching/binary_search_edge.rb new file mode 100644 index 000000000..dbdf95c08 --- /dev/null +++ b/codes/ruby/chapter_searching/binary_search_edge.rb @@ -0,0 +1,47 @@ +=begin +File: binary_search_edge.rb +Created Time: 2024-04-09 +Author: Blue Bean (lonnnnnnner@gmail.com) +=end + +require_relative './binary_search_insertion' + +### 二分查找最左一个 target ### +def binary_search_left_edge(nums, target) + # 等价于查找 target 的插入点 + i = binary_search_insertion(nums, target) + + # 未找到 target ,返回 -1 + return -1 if i == nums.length || nums[i] != target + + i # 找到 target ,返回索引 i +end + +### 二分查找最右一个 target ### +def binary_search_right_edge(nums, target) + # 转化为查找最左一个 target + 1 + i = binary_search_insertion(nums, target + 1) + + # j 指向最右一个 target ,i 指向首个大于 target 的元素 + j = i - 1 + + # 未找到 target ,返回 -1 + return -1 if j == -1 || nums[j] != target + + j # 找到 target ,返回索引 j +end + +### Driver Code ### +if __FILE__ == $0 + # 包含重复元素的数组 + nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15] + puts "\n数组 nums = #{nums}" + + # 二分查找左边界和右边界 + for target in [6, 7] + index = binary_search_left_edge(nums, target) + puts "最左一个元素 #{target} 的索引为 #{index}" + index = binary_search_right_edge(nums, target) + puts "最右一个元素 #{target} 的索引为 #{index}" + end +end diff --git a/codes/ruby/chapter_searching/binary_search_insertion.rb b/codes/ruby/chapter_searching/binary_search_insertion.rb new file mode 100644 index 000000000..5a0ee18cc --- /dev/null +++ b/codes/ruby/chapter_searching/binary_search_insertion.rb @@ -0,0 +1,68 @@ +=begin +File: binary_search_insertion.rb +Created Time: 2024-04-09 +Author: Blue Bean (lonnnnnnner@gmail.com) +=end + +### 二分查找插入点(无重复元素) ### +def binary_search_insertion_simple(nums, target) + # 初始化双闭区间 [0, n-1] + i, j = 0, nums.length - 1 + + while i <= j + # 计算中点索引 m + m = (i + j) / 2 + + if nums[m] < target + i = m + 1 # target 在区间 [m+1, j] 中 + elsif nums[m] > target + j = m - 1 # target 在区间 [i, m-1] 中 + else + return m # 找到 target ,返回插入点 m + end + end + + i # 未找到 target ,返回插入点 i +end + +### 二分查找插入点(存在重复元素) ### +def binary_search_insertion(nums, target) + # 初始化双闭区间 [0, n-1] + i, j = 0, nums.length - 1 + + while i <= j + # 计算中点索引 m + m = (i + j) / 2 + + if nums[m] < target + i = m + 1 # target 在区间 [m+1, j] 中 + elsif nums[m] > target + j = m - 1 # target 在区间 [i, m-1] 中 + else + j = m - 1 # 首个小于 target 的元素在区间 [i, m-1] 中 + end + end + + i # 返回插入点 i +end + +### Driver Code ### +if __FILE__ == $0 + # 无重复元素的数组 + nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35] + puts "\n数组 nums = #{nums}" + # 二分查找插入点 + for target in [6, 9] + index = binary_search_insertion_simple(nums, target) + puts "元素 #{target} 的插入点的索引为 #{index}" + end + + # 包含重复元素的数组 + nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15] + puts "\n数组 nums = #{nums}" + # 二分查找插入点 + for target in [2, 6, 20] + index = binary_search_insertion(nums, target) + puts "元素 #{target} 的插入点的索引为 #{index}" + end +end diff --git a/codes/ruby/chapter_searching/hashing_search.rb b/codes/ruby/chapter_searching/hashing_search.rb new file mode 100644 index 000000000..0683a142a --- /dev/null +++ b/codes/ruby/chapter_searching/hashing_search.rb @@ -0,0 +1,47 @@ +=begin +File: hashing_search.rb +Created Time: 2024-04-09 +Author: Blue Bean (lonnnnnnner@gmail.com) +=end + +require_relative '../utils/list_node' + +### 哈希查找(数组) ### +def hashing_search_array(hmap, target) + # 哈希表的 key: 目标元素,value: 索引 + # 若哈希表中无此 key ,返回 -1 + hmap[target] || -1 +end + +### 哈希查找(链表) ### +def hashing_search_linkedlist(hmap, target) + # 哈希表的 key: 目标元素,value: 节点对象 + # 若哈希表中无此 key ,返回 None + hmap[target] || nil +end + +### Driver Code ### +if __FILE__ == $0 + target = 3 + + # 哈希查找(数组) + nums = [1, 5, 3, 2, 4, 7, 5, 9, 10, 8] + # 初始化哈希表 + map0 = {} + for i in 0...nums.length + map0[nums[i]] = i # key: 元素,value: 索引 + end + index = hashing_search_array(map0, target) + puts "目标元素 3 的索引 = #{index}" + + # 哈希查找(链表) + head = arr_to_linked_list(nums) + # 初始化哈希表 + map1 = {} + while head + map1[head.val] = head + head = head.next + end + node = hashing_search_linkedlist(map1, target) + puts "目标节点值 3 的对应节点对象为 #{node}" +end diff --git a/codes/ruby/chapter_searching/linear_search.rb b/codes/ruby/chapter_searching/linear_search.rb new file mode 100644 index 000000000..08141a7a1 --- /dev/null +++ b/codes/ruby/chapter_searching/linear_search.rb @@ -0,0 +1,44 @@ +=begin +File: linear_search.rb +Created Time: 2024-04-09 +Author: Blue Bean (lonnnnnnner@gmail.com) +=end + +require_relative '../utils/list_node' + +### 线性查找(数组) ### +def linear_search_array(nums, target) + # 遍历数组 + for i in 0...nums.length + return i if nums[i] == target # 找到目标元素,返回其索引 + end + + -1 # 未找到目标元素,返回 -1 +end + +### 线性查找(链表) ### +def linear_search_linkedlist(head, target) + # 遍历链表 + while head + return head if head.val == target # 找到目标节点,返回之 + + head = head.next + end + + nil # 未找到目标节点,返回 None +end + +### Driver Code ### +if __FILE__ == $0 + target = 3 + + # 在数组中执行线性查找 + nums = [1, 5, 3, 2, 4, 7, 5, 9, 10, 8] + index = linear_search_array(nums, target) + puts "目标元素 3 的索引 = #{index}" + + # 在链表中执行线性查找 + head = arr_to_linked_list(nums) + node = linear_search_linkedlist(head, target) + puts "目标节点值 3 的对应节点对象为 #{node}" +end diff --git a/codes/ruby/chapter_searching/two_sum.rb b/codes/ruby/chapter_searching/two_sum.rb new file mode 100644 index 000000000..c311322d1 --- /dev/null +++ b/codes/ruby/chapter_searching/two_sum.rb @@ -0,0 +1,46 @@ +=begin +File: two_sum.rb +Created Time: 2024-04-09 +Author: Blue Bean (lonnnnnnner@gmail.com) +=end + +### 方法一:暴力枚举 ### +def two_sum_brute_force(nums, target) + # 两层循环,时间复杂度为 O(n^2) + for i in 0...(nums.length - 1) + for j in (i + 1)...nums.length + return [i, j] if nums[i] + nums[j] == target + end + end + + [] +end + +### 方法二:辅助哈希表 ### +def two_sum_hash_table(nums, target) + # 辅助哈希表,空间复杂度为 O(n) + dic = {} + # 单层循环,时间复杂度为 O(n) + for i in 0...nums.length + return [dic[target - nums[i]], i] if dic.has_key?(target - nums[i]) + + dic[nums[i]] = i + end + + [] +end + +### Driver Code ### +if __FILE__ == $0 + # ======= Test Case ======= + nums = [2, 7, 11, 15] + target = 13 + + # ====== Driver Code ====== + # 方法一 + res = two_sum_brute_force(nums, target) + puts "方法一 res = #{res}" + # 方法二 + res = two_sum_hash_table(nums, target) + puts "方法二 res = #{res}" +end