Recursive Multiplier in ruby - ruby

I am trying to create a recursive multiplier in ruby.
#j = 0
def multiplier(x, y, z)
count = 0
if x > 0
if z > 0
#j += y
z -= 1
count += 1
multiplier(x, y, z)
else
x -= 1
z = count
p z
multiplier(x, y, z)
end
else
return #j
end
end
def main
puts "Calculation is: " + multiplier(3, 10, 4).to_s
end
main
X is how many times the multiplication happens
Y is the number we want to multiply
Z is the number we multiply by
The code should output 120 with the variables that are there
I am having issues getting Z to stay what I need it to be. Also, I'd prefer to do this without a global variable
So something like x*(y*z) but without the times symbol

The main issue with your code is count is a local variable, it is not saved between recursive calls. Also, if you want to avoid globals, pass the variable as an additional parameter in call to the function. In FP we call it accumulator:
def multiplier(x, y, z, j = 0)
if z > 0
multiplier(x, y, z - 1, j + y)
elsif z.zero? # done with z, jump to x × (y × z)
# z = -1 to explicitly mark we are done with z
multiplier(x, j, -1, 0)
elsif y.zero? # yay, we are all set, reducing is done!
j
else
# still doing x × result step
multiplier(x, y - 1, -1, j + x)
end
end
multiplier(3, 10, 4)
#⇒ 120
The above surely lacks necessary checks for input validity, but I bet you got the idea.

Building on the recursive answer above, here's a more generic function that can take an arbitrarily long list of positive integers and multiply them by recursive addition:
def multiplier(*integers, accum: 0)
if integers.size == 1
# We are finished!
integers[0]
elsif integers[-1].positive?
# "Multiply" the last two integers, by recursive addition
integers[-1] -= 1
multiplier(*integers, accum: accum + integers[-2])
else
# The above multiplication is complete; set the last integer to its result
integers[-2] = accum
multiplier(*integers[0..-2])
end
end

I would say the idiomatic way in ruby is using iterators instead of recursion/cycles
def multiplier(x, y, z)
x.times.map do
y.times.map do
z
end.reduce(:+)
end.reduce(:+)
end
or
def multiplier(x, y, z)
x.times.map do
y.times.map do
z
end
end.flatten.reduce(:+)
end
Or if the only operation is inc
def multiplier(x, y, z)
j = 0
x.times do
y.times do
z.times do
j += 1
end
end
end
j
end
the output is the same
multiplier(3, 10, 4)
# 120
For an arbitrary number of args we have to use recursion
def multiplier(*xs, res: 0)
return res if xs.empty?
xs[0].times do
res += 1 if xs.size == 1
res = multiplier(*xs.drop(1), res: res)
end
res
end
or
def multiplier(*xs, res: 0)
head, *tail = xs
head.to_i.times do
res += 1 if tail.empty?
res = multiplier(*tail, res: res)
end
res
end

I'd start by writing a method to multiply two numbers recursively:
def multiply_2(a, b)
return 0 if a.zero?
b + multiply_2(a - 1, b)
end
multiply_2(3, 4)
#=> 12
and build upon that method to multiply three numbers:
def multiply_3(a, b, c)
multiply_2(multiply_2(a, b), c)
end
multiply_3(3, 4, 10)
#=> 3
and eventually extend that to handle n numbers:
def multiply_n(a, b, *more)
result = multiply_2(a, b)
return result if more.empty?
multiply_n(result, *more)
end
multiply_n(3, 4, 10, 2)
#=> 240
Note that you might run into a SystemStackError for large numbers. This can be avoided by making multiply_2 tail-recursive (leaving that as an exercise, it's not hard) and enabling Ruby's :tailcall_optimization.

It could be written thusly.
def multiplier(*args)
prod = recurse(*args.map(&:abs))
args.count { |n| n < 0 }.even? ? prod : -prod
end
def recurse(first, *rest)
first.zero? || rest.empty? ? first : ([recurse(*rest)]*first).sum
end
multiplier(3, 10, 4) #=> 120
multiplier(3, 10, 4, 2, 3) #=> 720
multiplier(3, -10, 4) #=> -120
multiplier(3, -10, -4) #=> 120
multiplier(3, 0, 4) #=> 0
multiplier(3, 0, -4) #=> 0
Suppose we wish to compute multiplier(3, -4). recurse(3, 4) is called, where
first = 3
rest = [4]
first.zero? #=> false
rest.empty? #=> false
so we compute
([recurse(4)]*3).sum
In recurse(4),
first = 4
rest = []
As rest.empty #=> true, recurse returns first #=> 4, so
([recurse(4)]*3).sum]
#=> ([4]*3).sum => [4,4,4].sum => 12
is returned to multiplier. As [3, -4] contains an odd number of negative values, multiplier returns -12.

Related

The Number of the Smallest Unoccupied Chair solution in ruby

I am learning ruby and have started practicing problems from leetcode, yesterday I have a problem which I am not able to solve since yesterday.
I tried hard doing that in ruby, but not able to do yet.
I tried this
def give_chair(a)
u = a.uniq
d = []
u.each do |i|
d << i if a.count(i) == 1
end
d
end
def smallest_chair(times, target_friend)
friend = times[target_friend]
sorted_arrival_times = times.sort
leave_time_chair = {}
chair = 0
chairs_array = []
uniq_chars_array = []
sorted_arrival_times.each do |i|
if leave_time_chair.keys.select { |k| i[0] > k }.empty?
leave_time_chair[i[1]] = chair
chair+=1
else
all_keys = leave_time_chair.keys.select { |k| k <= i[0] }
chairs_array = leave_time_chair.values
p chairs_array
if give_chair(chairs_array).empty?
leave_time_chair[i[1]] = chairs_array.sort.first
else
leave_time_chair[i[1]] = give_chair(chairs_array).sort.first
end
end
if i == friend
p leave_time_chair
return leave_time_chair[i[1]]
end
end
end
# a = [[33889,98676],[80071,89737],[44118,52565],[52992,84310],[78492,88209],[21695,67063],[84622,95452],[98048,98856],[98411,99433],[55333,56548],[65375,88566],[55011,62821],[48548,48656],[87396,94825],[55273,81868],[75629,91467]]
# b = 6
# p smallest_chair(a, b)
but it is failing for some test cases.
I am not able to create an algorithm for it.
Question = https://leetcode.com/problems/the-number-of-the-smallest-unoccupied-chair
My approach:
First I sort the times array according to arrival times.
Then I iterate over each array element
Now if the arrival time is greater than all the previous leaving time (I am creating key, value pair of leaving time and chair given) then I add a new key=> value pair in leave_time_chair (which is hash) and where key is the leaving time of current array and value is the chair given to it.
Then I increment the chair (chair+=1)
Else I get all those leaving time which are equal or less than the current arrival time (all_keys = leave_time_chair.keys.select { |k| k <= i[0] })
Then I get all the chairs of those times
Now I have all the chairs like this => [0, 0, 1, 2] so I wrote one function [ give_chair(a) ] which gives me those elements which are not repeated. like this => [1, 2] and then I assign the shortest number (chair) to the leaving time of current array. and so on...
Then if my current array is equal to the friend I return the chair of it. by extracting it from a hash (leave_time_chair) return leave_time_chair[i[1]]
my naive solution (not optimize yet), basically my idea that i flat-map the input array into an array with each element is a pair [time arrive/leave, friend index], then i will sort that array base on time (don't care arrive or leave), if both pair have same time, then i'll compare the arrive time of fiend index. Finally i loop through the sorted array and evaluate minimum free chair index each step, whenever i meet the targetFriend i return that minimum free chair index.
# #param {Integer[][]} times
# #param {Integer} target_friend
# #return {Integer}
def smallest_chair(times, target_friend)
# times = [[1,2],[4,7],[2,4]]
# targetFriend = 1
sit_times = times.each_with_index.inject([]) { |combi, (time, index)|
combi += [[time.first, index], [time.last, index]]
}
# [[1, 0], [2, 0], [4, 1], [7, 1], [2, 2], [4, 2]]
sit_times.sort! {|x, y|
c = x[0] <=> y[0]
# [[1, 0], [2, 0], [2, 2], [4, 1], [4, 2], [7, 1]]
c = times[x[1]][0] <=> times[y[1]][0] if c == 0
# [[1, 0], [2, 0], [2, 2], [4, 2], [4, 1], [7, 1]]
c
}
chairs = {} # to mark time of friend
occupied = Array.new(times.size, 0) # occupied chair: 1, otherwise: 0
min_free = 0 # current minimum not occupied chair
sit_times.each do |time, friend_index|
if target_friend == friend_index # check
return min_free
end
sit = chairs[friend_index]
if sit # leave
occupied[sit] = 0
chairs[friend_index] = nil
min_free = sit if min_free > sit
else # arrive
chairs[friend_index] = min_free
occupied[min_free] = 1
min_free += 1 until occupied[min_free] == 0 # re-calculate
end
end
end
Note: the code pass test cases on leetcode but the performance is not good.
update
here is the better version, using 3 priority queues, one for arrive times, one for leave times and the last for chair.
PriorityQueue class
class PriorityQueue
attr_reader :length
def initialize(opts={}, &comparator)
order_opt = opts.fetch(:order, :asc)
#order = order_opt == :asc ? -1 : 1
#comparator = comparator
#items = [nil]
#length = 0
end
def push(item)
#items << item
#length += 1
swim(#length)
true
end
def pop
return nil if empty?
swap(1, #length) if #length > 1
#length -= 1
sink(1) if #length > 0
#items.pop
end
def empty?
#length == 0
end
def swap(i, j)
temp = #items[i]
#items[i] = #items[j]
#items[j] = temp
end
def in_order?(i, j)
x = #items[i]
y = #items[j]
order = #comparator.nil? ? (x <=> y) : #comparator.call(x, y)
order == #order
end
def swim(from)
while (up = from / 2) >= 1
break if in_order?(up, from)
swap(up, from)
from = up
end
end
def sink(from)
while (down = from * 2) <= #length
down += 1 if down < #length && in_order?(down + 1, down)
break if in_order?(from, down)
swap(down, from)
from = down
end
end
end
smallest_chair with priority queues (note that i found using sort is faster than a queue for arrive times, but basically the idea is same)
def smallest_chair_pq(times, target_friend)
# a_pq = PriorityQueue.new { |x, y|
# x[0] <=> y[0]
# }
#
# times.each do |t|
# a_pq.push(t)
# end
# sort arrive times is faster than a priority queue
a_pq = times.sort_by(&:first).reverse
# leave times queue
l_pq = PriorityQueue.new { |x, y|
c = x[0] <=> y[0]
c = x[1] <=> y[1] if c == 0
c
}
# chair-indexes queue
# consider case a friend come in at arrive-time at1
# and there's a range chairs with leave times in range lm <= at1 <= ln
# that mean that friend could pick one of those chairs
# and according this problem requirement, should pick the minimun chair index
c_pq = PriorityQueue.new
target_time = times[target_friend][0]
last_chair_index = 0
until a_pq.empty?
a_top = a_pq.pop
arrive_time = a_top.first
if l_pq.empty?
return 0 if arrive_time == target_time
l_pq.push([a_top.last, 0])
else
l_top = l_pq.pop
if l_top.first <= arrive_time
c_pq.push(l_top.last)
until (l_ntop = l_pq.pop).nil? || arrive_time < l_ntop.first
c_pq.push(l_ntop.last)
end
l_pq.push(l_ntop) unless l_ntop.nil?
min_chair_index = c_pq.pop
return min_chair_index if arrive_time == target_time
l_pq.push([a_top.last, min_chair_index])
else
unless c_pq.empty?
chair_index = c_pq.pop
return chair_index if arrive_time == target_time
l_pq.push([a_top.last, chair_index])
else
last_chair_index += 1
return last_chair_index if arrive_time == target_time
l_pq.push([a_top.last, last_chair_index])
end
l_pq.push(l_top)
end
end
end
end

How to loop over an entire method until you achieve what you want ? (ruby)

I'm learning ruby and practicing with codewars, and I've come to a challenge that I feel I mainly understand (rudimentarily) but I'm unable to figure out how to continue looping over the method until I reach the result I'm looking for.
The challenge is asking to reduce a number, by multiplying its digits, until the multiplication results in a single digit. In the end it wants you to return the number of times you had to multiply the number until you arrived at a single digit. Example -> given -> 39; 3 * 9 = 27, 2 * 7 = 14, 1 * 4 = 4; answer -> 3
Here's my code :
def persistence(n)
if n < 10
return 0
end
arr = n.to_s.split("")
sum = 1
count = 0
arr.each do |num|
sum *= num.to_i
if num == arr[-1]
count += 1
end
end
if sum < 10
return count
else
persistence(sum)
end
end
Thanks for your help!
Your function is looking great with recursion but you are reseting the count variable to 0 each time the loop runs, I think if you use an auxiliar method it should run ok:
this is in base of your code with minor improvements:
def persistence(n)
return 0 if n < 10
count = 0
multiply_values(n, count)
end
def multiply_values(n, count)
arr = n.to_s.chars
sum = 1
arr.each do |num|
sum *= num.to_i
if num == arr[-1]
count += 1
end
end
if sum < 10
return count
else
multiply_values(sum, count)
end
end
a shorter solution could be to do:
def persistence(n)
return 0 if n < 10
multiply_values(n, 1)
end
def multiply_values(n, count)
sum = n.to_s.chars.map(&:to_i).reduce(&:*)
return count if sum < 10
multiply_values(sum, count + 1)
end
and without recursion:
def persistence(n)
return 0 if n < 10
count = 0
while n > 10
n = n.to_s.chars.map(&:to_i).reduce(&:*)
count += 1
end
count
end
Let's look at a nicer way to do this once:
num = 1234
product = num.to_s.split("").map(&:to_i).reduce(&:*)
Breaking it down:
num.to_s.split("")
As you know, this gets us ["1", "2", "3", "4"]. We can easily get back to [1, 2, 3, 4] by mapping the #to_i method to each string in that array.
num.to_s.split("").map(&:to_i)
We then need to multiply them together. #reduce is a handy method. We can pass it a block:
num.to_s.split("").map(&:to_i).reduce { |a, b| a * b }
Or take a shortcut:
num.to_s.split("").map(&:to_i).reduce(&:*)
As for looping, you could employ recursion, and create product_of_digits as a new method for Integer.
class Integer
def product_of_digits
if self < 10
self
else
self.to_s.split("").map(&:to_i).reduce(&:*).product_of_digits
end
end
end
We can now simply call this method on any integer.
1344.product_of_digits # => 6

Method not returning the expected value in Ruby

I was trying to implement Karatsuba multiplication in Ruby..
# takes two integer x and y and partition them to x=a+b and y=c+d
# example if x = 1234 a=12 and b=34
# recursively compute a*c,a*d,b*c and b*d
def mult (x,y)
if len(x) == 1 && len(y) == 1
return x*y
elsif len(x) > 1 && len(y) > 1
ab = partition(x)
cd = partition(y)
return ab.product(cd).each{ |num| mult(num[0],num[1]) }
end
end
#method for partitioning works fine..
def partition(number)
number.divmod( 10**(len(number)/2) )
end
#method to find size of integer works fine...
def len(value)
value.to_s.split("").compact.size
end
So the expected return for
p mult(12,34) should be 3,4,6,8
but is [[1, 3], [1, 4], [2, 3], [2, 4]]
instead of return x*y, when i use print "#{x*y}" in line no:3 it prints 3,4,6,8. I am unable to understand why mult method is returning nil for x*y.
The problem is wrong iterator:
# ⇓⇓⇓⇓
ab.product(cd).each{ |num| mult(num[0],num[1]) }
What you want is to Enumerable#map instead:
ab.product(cd).map { |num| mult(num[0], num[1]) }
Sidenote: you also don’t need to explicitly call return:
def mult (x,y)
if len(x) == 1 && len(y) == 1
x*y
elsif len(x) > 1 && len(y) > 1
ab = partition(x)
cd = partition(y)
ab.product(cd).map { |num| mult(num[0], num[1]) }
else
raise "We got a problem"
end
end
#method for partitioning works fine..
def partition(number)
number.divmod( 10**(len(number)/2) )
end
#method to find size of integer works fine...
def len(value)
value.to_s.size
end
p mult 12, 34
#⇒ [3,4,6,8]

Partial Fibonacci Sum, how to improve performance?

I need to improve the performance of this algorithm. I believe the answer lies in the application of the pisano period.
This algorithm must return the last digit of the sum of fib numbers from f(m) to f(n).
Here is what I have so far:
def fib(n)
a = []
a << 0 << 1
(n+1).times do |i|
a << a[-1] + a[-2]
end
a[n]
end
def fib_partial_sum(m, n)
if n == m
fib(m) % 10
else
m = fib(m + 1) - 1
n = fib(n + 2) - 1
(n - m) % 10
end
end
if __FILE__ == $0
m, n = gets.split().map(&:to_i)
puts "#{fib_partial_sum(m, n)}"
end
The last digit of any fib num repeats every 60 numbers. Therefore, we can do this, n, m = n % 60, m % 60. An improvement, but not quite there yet, fails on input 567717153638 567717153638):
def fib(n)
a = []
a << 0 << 1
(n+1).times do |i|
a << a[-1] + a[-2]
end
a[n]
end
def fib_partial_sum(m, n)
if n == m
fib(m)
else
m = m % 60
n = n % 60
m = fib(m + 1) - 1
n = fib(n + 2) - 1
(n - m) % 10
end
end
if __FILE__ == $0
m, n = gets.split().map(&:to_i)
puts "#{fib_partial_sum(m, n)}"
end
Here is a nice solution to the problem, it passes all time and memory constraints.
This way you never have to calculate a fib num greater that f(60). It can handle very large inputs efficiently.
def fib(n)
a, b = 0, 1
(n-1).times do
a, b = b, (a + b) % 10
end
b
end
def fib_partial_sum(m, n)
if n == m
fib(m % 60)
else
m = m % 60
n = n % 60
m = fib(m + 1) - 1
n = fib(n + 2) - 1
(n - m) % 10
end
end
if __FILE__ == $0
m, n = gets.split().map(&:to_i)
puts "#{fib_partial_sum(m, n)}"
end
(Max time used: 0.05/5.00, max memory used: 8699904/536870912.)
The following requires only a single pass of the numbers between zero and at most [n,m+60].min, where m..n is the range of interest, and has a minimal memory requirement. It makes use of #nloveladyallen's observation that the last digit of Fibonacci numbers has a periodicity of 60.
Code
def fib_last(m,n)
n -= 60*((n-m)/60)
fib_sum(m,n) % 10
end
def fib_sum(m,n)
return nil if m < 0 || m > n
return n if n < 2
next_to_last, last = fib(m-1)
(m..n).reduce(0) do |tot,_|
current = next_to_last + last
next_to_last = last
last = current
tot + current
end
end
def fib(m)
next_to_last, last = -1, 1
0.upto(m).each do |n|
current = next_to_last + last
next_to_last, last = last, current
end
[next_to_last, last]
end
Example
m, n = 6, 12
(n+1).times { |i| puts "#{i}: #{fib(i)}" }
0: [0, 0]
1: [0, 1]
2: [1, 1]
3: [1, 2]
4: [2, 3]
5: [3, 5]
6: [5, 8]
7: [8, 13]
8: [13, 21]
9: [21, 34]
10: [34, 55]
11: [55, 89]
12: [89, 144]
fib_last(6,12) #=> 4 (fib_sum(6,12) #=> 8 + 13 + 21 + 34 + 55 + 89 + 144 = 364)
fib_last(1,2) #=> 2 (fib_sum(1,2) #=> 1 + 1 = 2)
fib_last(1,3) #=> 4 (fib_sum(1,3) #=> 1 + 1 + 2 = 4)
fib_last(1,4) #=> 7 (fib_sum(1,4) #=> 1 + 1 + 2 + 3 = 7)
fib_last(2,3) #=> 3 (fib_sum(2,3) #=> 1 + 2 = 3)

Project Euler #3 Ruby

The task:
The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143?
The correct answer is 6857.
My code:
def prime?(n)
(2..(n-1)).each { |x| false if n % x == 0 }
true
end
x = 2
prime_factor_arr = []
number = 600_851_475_143
while x < number
if number % x == 0 && prime?(x)
prime_factor_arr << x
number = number / x
end
x += 1
end
puts prime_factor_arr.last
puts prime?(prime_factor_arr.last)
puts prime_factor_arr
In the above case, I get 1471 as the largest prime. If I change the code to:
while x < (number / x)
if number % x == 0 && prime?(x)
prime_factor_arr << x
end
x += 1
end
I get 486847. The array printed in the end is:
[71, 839, 1471, 6857, 59569, 104441, 486847]
It is not clear to me why my code does not work. Could anybody help?
For the answer to the question, Sergio is right. But the code Sergio suggests (as well as yours) will not work correctly when number is a prime itself.
A better way to write is:
def prime?(n); (2...n).none?{|x| n.%(x).zero?} end
number = 600_851_475_143
number.downto(1).find{|x| number.%(x).zero? and prime?(x)}
Try this.
def prime? n
(2..(n-1)).each { |x| return false if n % x == 0 }
true
end
n = 600_851_475_143
a = []
product_sum = 1
x = 2 # 2 is the first prime number
while product_sum < n
if n % x == 0 && prime?(x)
a << x
product_sum *= x
end
x += 1
end
puts "The answer is #{a.last}"
The prime lib (from standard lib) is very nice for Project Euler. But it takes the fun out of this one:
require "prime"
600851475143.prime_division.last.first # => 6857

Resources