Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add Ruby code - chapter "Searching" #1262

Merged
merged 12 commits into from
Apr 11, 2024
63 changes: 63 additions & 0 deletions codes/ruby/chapter_searching/binary_search.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
=begin
File: binary_search.rb
Created Time: 2024-04-09
Author: Blue Bean ([email protected])
=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
47 changes: 47 additions & 0 deletions codes/ruby/chapter_searching/binary_search_edge.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
=begin
File: binary_search_edge.rb
Created Time: 2024-04-09
Author: Blue Bean ([email protected])
=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
68 changes: 68 additions & 0 deletions codes/ruby/chapter_searching/binary_search_insertion.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
=begin
File: binary_search_insertion.rb
Created Time: 2024-04-09
Author: Blue Bean ([email protected])
=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
47 changes: 47 additions & 0 deletions codes/ruby/chapter_searching/hashing_search.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
=begin
File: hashing_search.rb
Created Time: 2024-04-09
Author: Blue Bean ([email protected])
=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
44 changes: 44 additions & 0 deletions codes/ruby/chapter_searching/linear_search.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
=begin
File: linear_search.rb
Created Time: 2024-04-09
Author: Blue Bean ([email protected])
=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
46 changes: 46 additions & 0 deletions codes/ruby/chapter_searching/two_sum.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
=begin
File: two_sum.rb
Created Time: 2024-04-09
Author: Blue Bean ([email protected])
=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