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 codes - chapter "Greedy" #1350

Merged
merged 1 commit into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions codes/ruby/chapter_greedy/coin_change_greedy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
=begin
File: coin_change_greedy.rb
Created Time: 2024-05-07
Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com)
=end

### 零钱兑换:贪心 ###
def coin_change_greedy(coins, amt)
# 假设 coins 列表有序
i = coins.length - 1
count = 0
# 循环进行贪心选择,直到无剩余金额
while amt > 0
# 找到小于且最接近剩余金额的硬币
while i > 0 && coins[i] > amt
i -= 1
end
# 选择 coins[i]
amt -= coins[i]
count += 1
end
# 若未找到可行方案, 则返回 -1
amt == 0 ? count : -1
end

### Driver Code ###
if __FILE__ == $0
# 贪心:能够保证找到全局最优解
coins = [1, 5, 10, 20, 50, 100]
amt = 186
res = coin_change_greedy(coins, amt)
puts "\ncoins = #{coins}, amt = #{amt}"
puts "凑到 #{amt} 所需的最少硬币数量为 #{res}"

# 贪心:无法保证找到全局最优解
coins = [1, 20, 50]
amt = 60
res = coin_change_greedy(coins, amt)
puts "\ncoins = #{coins}, amt = #{amt}"
puts "凑到 #{amt} 所需的最少硬币数量为 #{res}"
puts "实际上需要的最少数量为 3 , 即 20 + 20 + 20"

# 贪心:无法保证找到全局最优解
coins = [1, 49, 50]
amt = 98
res = coin_change_greedy(coins, amt)
puts "\ncoins = #{coins}, amt = #{amt}"
puts "凑到 #{amt} 所需的最少硬币数量为 #{res}"
puts "实际上需要的最少数量为 2 , 即 49 + 49"
end
51 changes: 51 additions & 0 deletions codes/ruby/chapter_greedy/fractional_knapsack.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
=begin
File: fractional_knapsack.rb
Created Time: 2024-05-07
Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com)
=end

### 物品 ###
class Item
attr_accessor :w # 物品重量
attr_accessor :v # 物品价值

def initialize(w, v)
@w = w
@v = v
end
end

### 分数背包:贪心 ###
def fractional_knapsack(wgt, val, cap)
# 创建物品列表,包含两个属性:重量,价值
items = wgt.each_with_index.map { |w, i| Item.new(w, val[i]) }
# 按照单位价值 item.v / item.w 从高到低进行排序
items.sort! { |a, b| (b.v.to_f / b.w) <=> (a.v.to_f / a.w) }
# 循环贪心选择
res = 0
for item in items
if item.w <= cap
# 若剩余容量充足,则将当前物品整个装进背包
res += item.v
cap -= item.w
else
# 若剩余容量不足,则将当前物品的一部分装进背包
res += (item.v.to_f / item.w) * cap
# 已无剩余容量,因此跳出循环
break
end
end
res
end

### Driver Code ###
if __FILE__ == $0
wgt = [10, 20, 30, 40, 50]
val = [50, 120, 150, 210, 240]
cap = 50
n = wgt.length

# 贪心算法
res = fractional_knapsack(wgt, val, cap)
puts "不超过背包容量的最大物品价值为 #{res}"
end
37 changes: 37 additions & 0 deletions codes/ruby/chapter_greedy/max_capacity.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
=begin
File: max_capacity.rb
Created Time: 2024-05-07
Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com)
=end

### 最大容量:贪心 ###
def max_capacity(ht)
# 初始化 i, j,使其分列数组两端
i, j = 0, ht.length - 1
# 初始最大容量为 0
res = 0

# 循环贪心选择,直至两板相遇
while i < j
# 更新最大容量
cap = [ht[i], ht[j]].min * (j - i)
res = [res, cap].max
# 向内移动短板
if ht[i] < ht[j]
i += 1
else
j -= 1
end
end

res
end

### Driver Code ###
if __FILE__ == $0
ht = [3, 8, 5, 2, 7, 7, 3, 4]

# 贪心算法
res = max_capacity(ht)
puts "最大容量为 #{res}"
end
28 changes: 28 additions & 0 deletions codes/ruby/chapter_greedy/max_product_cutting.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
=begin
File: max_product_cutting.rb
Created Time: 2024-05-07
Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com)
=end

### 最大切分乘积:贪心 ###
def max_product_cutting(n)
# 当 n <= 3 时,必须切分出一个 1
return 1 * (n - 1) if n <= 3
# 贪心地切分出 3 ,a 为 3 的个数,b 为余数
a, b = n / 3, n % 3
# 当余数为 1 时,将一对 1 * 3 转化为 2 * 2
return (3.pow(a - 1) * 2 * 2).to_i if b == 1
# 当余数为 2 时,不做处理
return (3.pow(a) * 2).to_i if b == 2
# 当余数为 0 时,不做处理
3.pow(a).to_i
end

### Driver Code ###
if __FILE__ == $0
n = 58

# 贪心算法
res = max_product_cutting(n)
puts "最大切分乘积为 #{res}"
end