This Fibonacci method works with small numbers but the calculations won't work when factored out very far. How can I store what is done at lower level cycles to be reused for later cycles?
def fib(n)
return 0 if n==0
return 1 if n==1
fib(n-1) + fib(n-2)
end
Here's a very basic way to memoize a method like this with a Hash.
#fib_memo = {}
def fib(n)
return 0 if n == 0
return 1 if n == 1
return #fib_memo[n] if #fib_memo.key?(n)
#fib_memo[n] = fib(n - 1) + fib(n - 2)
end
And it doesn't take much imagination to see how that could be shortened to this:
#fib_memo = { 0 => 0, 1 => 1 }
def fib(n)
#fib_memo[n] ||= fib(n - 1) + fib(n - 2)
end
Or, as spickermann demonstrates, you can do it all in a Hash's default proc, but that's just showing off. ;)
You could use a hash to store lower level cycles:
fibonacci = Hash.new { |h, k| h[k] = k < 2 ? k : h[k-1] + h[k-2] }
fibonacci[100]
#=> 354224848179261915075
Related
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
I'm currently going over Robert Sedgewick's Algorithms book. In the book for the implementation of a Priority Queue there is the use of the Comparable module. While going over the top k frequent elements leetcode problem I noticed that there would be an error in my Ruby implementation.
def top_k_frequent(nums, k)
ans = []
h = Hash.new(0)
nums.each do |num|
h[num] += 1
end
heap = Heap.new
h.each do |k,v|
heap.insert({k => v})
end
k.times do
a = heap.del_max
ans.push(a.keys[0])
end
ans
end
class Heap
def initialize
#n = 0
#pq = []
end
def insert(v)
#pq[#n += 1] = v
swim(#n)
end
def swim(k)
while k > 1 && less((k / 2).floor, k)
swap((k / 2).floor, k)
k = k/2
end
end
def swap(i, j)
temp = #pq[i]
#pq[i] = #pq[j]
#pq[j] = temp
end
def less(i, j)
#pq[i].values[0] < #pq[j].values[0]
end
def del_max
max = #pq[1]
swap(1, #n)
#n -= 1
#pq[#n + 1] = nil
sink(1)
max
end
def sink(k)
while 2 * k <= #n
j = 2 * k
if !#pq[j + 1].nil?
j += 1 if j > 1 && #pq[j].values[0] < #pq[j + 1].values[0]
end
break if !less(k, j)
swap(k, j)
k = j
end
end
end
Above is the Java Priority Queue implementation.
Ruby's comparable operator is <=> which will return one of -1, 0, 1 and nil (nil mean could not compare).
In order to compare two objects , both need to implement a method def <=>(other). This is not on Object, so is not available on any objects that don't implement it or extend from a class that does implement it. Numbers and Strings, for example, do have an implementation. Hashes do not.
I think in your case, the issue is slightly different.
When you call queue.insert(my_hash) what you're expecting is for the algorithm to break up my_hash and build from that. Instead, the algorithm takes the hash as a single, atomic object and inserts that.
If you add something like:
class Tuple
attr_accessor :key, :value
def initialize(key, value)
#key = key
#value = value
end
def <=>(other)
return nil unless other.is_a?(Tuple)
value <=> other.value
end
end
then this will allow you to do something like:
hsh = { 1 => 3, 2 => 2, 3 => 1}
tuples = hsh.map { |k, v| Tuple.new(k, v) }
tuples.each { |tuple| my_heap.insert(tuple) }
you will have all of your data in the heap.
When you retrieve an item, it will be a tuple, so you can just call item.key and item.value to access the data.
I've just started learning ruby, and the position of where variables are defined somewhat elude me. For example, why does this code work:
def two_sum(nums)
result = nil
i = 0
while i < nums.length
k = (nums.length - 1)
if nums[i] + nums[k] == 0
result = [i,k]
end
i += 1
k -= 1
end
return result
end
And why does this code not work:
def two_sum(nums)
result = nil
i = 0
k = (nums.length - 1)
while i < nums.length
if nums[i] + nums[k] == 0
result = [i,k]
end
i += 1
k -= 1
end
return result
end
Thank you in advance!
I think you code might just have a bug
while i < nums.length
k = (nums.length - 1)
...
k -= 1 # this statement has no effect!
end
Above, the value if k is always (nums.length - 1) because you reassign it at the begin of each iteration. The other statement has no effect.
k = (nums.length - 1)
while i < nums.length
...
k -= 1
end
Above, the value of k starts at (nums.length - 1) in the first iteration and is then reduced by 1 for each iteration.
Pro tipp —
It is very unusual in Ruby to use a for/while/until loop. If you want to loop over all elements use each or each_with_index instead
array.each { |each| ... }
array.each_with_index { |each, n| ... }
factorial_sum(5) should return 3. The error I'm getting is that "inject is an undefined method". I was also wondering if it's possible to combine the two functions. I wasn't sure as I am just starting out on recursion. Thanks!
def factorial_sum(x)
factorial = factorial(x)
factorial.to_s.split('').collect { |i| i.to_i }
sum = factorial.inject { |sum, n| sum + n }
end
def factorial(x)
if x < 0
return "Negative numbers don't have a factorial"
elsif x == 0
1
else
factorial = x * factorial(x - 1)
end
end
puts factorial_sum(5)
factorial.to_s.split('').collect { |i| i.to_i }
This line is a no-op. You build a list and then throw it away. You probably meant factorial = ...
I have to say though that this would be pretty easy to find with a little effort and some print statements...
By the way, here's a slightly more concise way:
(1..x).reduce(:*).to_s.chars.map(&:to_i).reduce(:+)
A direct way without temporarily converting it into strings, and without recursion.
s, q = 0, 120
while q > 0
q, r = q.divmod(10)
s += r
end
s # => 3
I'm new to Ruby. After a ton of refactoring I came down to this. Is there a better way to write this?
51 def tri_num?(n)
52 i = 1
53 while i < n
54 return i if i * (i + 1) / 2 == n
55 i += 1
56 end
57 raise InvalidTree
58 end
What about solving it directly?
def tri_num? n
i = (0.5*(-1.0 + Math.sqrt(1.0 + 8.0*n))).to_i
if i*(i+1)/2 == n
return i
else
raise InvalidTree
end
end
Though I don't know if tri_num? is a good name. Usually a function ending with a ? should return true or false.
Yes.
def tri_num?(n)
1.upto(n-1) do |i|
return i if i * (i + 1) / 2 == n
end
raise InvalidTree
end
I thought the same as dantswain, basically invert the equation:
=> i * (i + 1) / 2 = n
=> i * (i + 1) = 2*n
=> i^2 + i = 2*n
=> i^2 + i -2*n = 0
And the solutions for the above are:
i = (-1 +- sqrt(1+8n))/2
Here I don't consider the - solution as it will give negative for any value of n bigger than 0, in the end the code is:
def tri_num?(n)
i = (-1 + Math.sqrt(1 + 8*n))/2.0
return i.to_i if i == i.to_i
raise InvalidTree
end
def tri_num?(n)
(1...n).each do |i|
return i if i * (i + 1) / 2 == n
end
rails InvalidTree # not defined..
end