mirror of
				https://github.com/krahets/hello-algo.git
				synced 2025-11-04 14:18:20 +08:00 
			
		
		
		
	feat: Add Ruby code - chapter "Searching" (#1262)
* create RUBY searching files & finish two_sum.rb * finish linear_search.rb * finish hashing_search.rb * finish binary_search.rb * finish binary_search_insertion.rb * finish binary_search_edge.rb * fix: change 'or' to '||' * fix: Adjust the code style(ruby searching) * fix: repair file name * fix: Adjust the output format * fix: fix 0...nums.length & delete useless require & change into __FILE__==0 block
This commit is contained in:
		
							
								
								
									
										63
									
								
								codes/ruby/chapter_searching/binary_search.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								codes/ruby/chapter_searching/binary_search.rb
									
									
									
									
									
										Normal file
									
								
							@ -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
 | 
			
		||||
							
								
								
									
										47
									
								
								codes/ruby/chapter_searching/binary_search_edge.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								codes/ruby/chapter_searching/binary_search_edge.rb
									
									
									
									
									
										Normal file
									
								
							@ -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
 | 
			
		||||
							
								
								
									
										68
									
								
								codes/ruby/chapter_searching/binary_search_insertion.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								codes/ruby/chapter_searching/binary_search_insertion.rb
									
									
									
									
									
										Normal file
									
								
							@ -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
 | 
			
		||||
							
								
								
									
										47
									
								
								codes/ruby/chapter_searching/hashing_search.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								codes/ruby/chapter_searching/hashing_search.rb
									
									
									
									
									
										Normal file
									
								
							@ -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
 | 
			
		||||
							
								
								
									
										44
									
								
								codes/ruby/chapter_searching/linear_search.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								codes/ruby/chapter_searching/linear_search.rb
									
									
									
									
									
										Normal file
									
								
							@ -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
 | 
			
		||||
							
								
								
									
										46
									
								
								codes/ruby/chapter_searching/two_sum.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								codes/ruby/chapter_searching/two_sum.rb
									
									
									
									
									
										Normal file
									
								
							@ -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
 | 
			
		||||
		Reference in New Issue
	
	Block a user