I'm currently working on small ruby projects from project Euler site. I was given a task to sum even fibonacci numbers that are less than 4 millions. Unfortunately there is a small bug in my code, because when I change the limit e.i. to 100, it prints 188 instead of 44. Surprisingly this program gives the right answer but i don't really know in what way my code is wrong.
a=[]; a[0]=1; a[1]=1;
i = 1
while a[-1] < 608
a[i+1]=(a[i] + a[i-1])
i +=1
end
x = 0
a.each do |num|
if num % 2 == 0
x += num
end
end
print "The sum of even Fibonacci number is: #{x}"
The problem comes from the second iteration. You are stopping the generation of Fibonacci numbers when one of the numbers cross the limit (ie when the last number is > 100).
It turns out that after the generation step, the array is [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144], this explains your wrong result 188 = 144+44.
So, your code works only when the last element generated is odd, which is the case in Euler's problem test. In order to correct that, change your second iteration from a.each do ... end to a[0...-1].each do ... end In order to iterate through the array except the last element.
BTW I would recommend you not to use an array here.
You are just wasting memory and ruby is losing time on extending it (this can be solved via Array.new(ARRAY_SIZE)).
Since you don't actually need a fibbonaci sequence you can just have something like this:
LIMIT = 4_000_000
a = 1
b = 1
next_number = a + b
sum = 0
while next_number < LIMIT
sum += next_number if next_number.even?
a = b
b = next_number
next_number = a + b # or next_number += a
end
UPD. Oh my god I don't know why this question appeared in my feed. Sorry for necroposting:)
Related
I'm practicing my coding chops after a long break and ran into this kata on CodeWars
With an input of numbers in an array, return the sums of its parts. So for example:
def parts_sums(ls)
sums = []
until ls.size == 0
sums << ls.inject(:+)
ls.shift
end
sums << 0
end
######### INPUT #######
parts_sums([0, 1, 3, 6, 10])
######### EXPECTED OUTPUT ######
[20, 20, 19, 16, 10, 0]
0 + 1 + 3 + 6 + 10 = 20
1 + 6 + 3 + 10 = 20
3 + 6 + 10 = 19
6 + 10 = 16
10 = 10
0 = 0
My solution solves the kata, however once I reach arrays of around 30,000+ my solution takes too long to solve.
So my question is to the community, how would I even attempt to make this go faster. I know that recursion is usually slow, and that for loops and its variants are usually sufficient to get the job done. What happens when that fails? What are some things to try to make my code above faster?
I'm looking for some advice and some examples if anyone has any. Appreciate the input. Thanks.
def parts_sums(ls)
ls.each_with_object([ls.sum]) { |n,arr| arr << arr.last - n }
end
parts_sums([0, 1, 3, 6, 10])
#=> [20, 20, 19, 16, 10, 0]
The issue with the code is that you are performing an inject on every iteration of your loop, which is unnecessarily slow.
You only need to sum the elements of the array once, outside of any loop. Once you have that sum, you can iterate through the elements of the array and perform a constant time subtraction from the current sum and push it into the sums array.
def part_sums(ls)
sum = ls.inject(:+)
sums = [sum]
ls.each do |val|
sum -= val
sums << sum
end
sums
end
There is also no need to shift, if you iterate through the array with the each iterator or keep a counter and use a while loop.
This version of the function runs much faster:
def parts_sums_2(ls)
sums = []
last_sum = 0
(ls.length - 1).downto(0).each do |i|
last_sum += ls[i]
sums.prepend last_sum
end
sums + [0]
end
The key here is going backwards through the array - starting with the smallest sum (only the last element). Each subsequent step moves one index towards the beginning, and adds that value to the previous sum.
Since the problem statement requires you to shift each step, your result must have the largest sums at the beginning, even though these are the last ones to be computed. This is why my code uses prepend rather than push.
This is O(N) time complexity instead of O(N^2), which is an order of magnitude difference.
With 100_000 inputs, your original function took 7.040443 seconds, while mine here took 0.000008 seconds
Also in general you should try to avoid mutating the input to your methods (as you were doing with shift).
I am trying to take the sum of the n first prime numbers. I found a way of showing the first 100, but I don't know how to get rid of 1 and how to make a sum with the numbers. I was thinking about storing them into an array, but I can not figure it out.
num = 1
last = 100
while (num <= last)
condition = true
x = 2
while (x <= num / 2)
if (num % x == 0)
condition = false
break
end
x = x + 1
end
primes = [] # Here
if condition
puts num.to_s
primes << num.to_s # Here
end
num = num + 1
end
puts primes.inject(:+) # Here
Based on what I understood from what you guys are saying I added these lines (the ones commented # Here). It still does not print the sum of them. What I meant with getting rid of 1 is that I know that 1 is not considered a prime number, and I do not get how to make it without 1. Thank you very much guys for your time and answers, and please understand that I am just starting to study this.
If you want to add a list of numbers together you can use the following:
list_of_prime_numbers.inject(0) {|total,prime| total + prime}
This will take the list of numbers, and add them one by one to an accumulator (total) that was injected into the loop (.inject(0)), add it to the current number (prime) and then return the total which then becomes the value of total in the next iteration.
I'm not quite sure what you mean by:
I don't know how to get rid of 1
but if you mean to not use the first number (which is 1 in a list of primes starting from 0)
then you could do:
list_of_prime_numbers[1...list_of_prime_numbers.length].
inject(0) {|total,prime| total + prime}
Which would only get all the numbers except the first up to but not including the length of the array
and as for getting the number into the array you could push it into the array like so:
list_of_prime_numbers << prime_number
You can make use of Prime Enumerable in ruby
require 'prime'
((1..100).select { |number| Prime.prime?(number) }).inject(:+)
OR
Prime.each(100).inject(:+)
Hope this helps.
I've spent a while on the following algorithm:
You are given coins of different denominations and a total amount of
money amount. Write a function to compute the fewest number of coins
that you need to make up that amount. If that amount of money cannot
be made up by any combination of the coins, return -1.
Example 1: coins = [1, 2, 5], amount = 11 return 3 (11 = 5 + 5 + 1)
Example 2: coins = [2], amount = 3 return -1.
Note: You may assume that you have an infinite number of each kind of
coin.
This is likely not the most efficient way to solve the problem, but I figured I can solve it by trying every coin and launching a new function per attempt, where the new function call has the updated amount. This would launch N function calls per coin... but I'll deal with that later.
Right now I'm dealing with the following issue: often when making recursive calls, I'm unable to properly code in a base case. For example, in this problem we have to return -1 if the amount of money cannot be made up by any combination of the coins. However, I also need to count up the fewest number of coins. So I figured I'd take a min variable and call 1 + new_func_call.
However, when this new_func_call ends up not working out, it passes up a -1 to the recursive call stack, which ends up making min zero instead. I'm not sure how to adjust this-- I've tried varying my code in different ways but perhaps I'm having a conceptual issue. I know why it's happening-- just don't know how to deal with it.
Sample input:
Coins: [2]
Amount: 3
My output: 0
Correct output: -1
Code:
def coin_change(coins, amount)
coin_count(coins, amount, coins.min)
end
def coin_count(coins, amount, min_coin)
with_coin = min = 1.0/0
return 0 if amount == 0
return -1 if amount < min_coin
i = 0
while i < coins.length
with_coin = 1 + coin_count(coins, amount - coins[i], min) if amount - coins[i] >= 0
min = [min, with_coin].min
i += 1
end
min
end
Right now I'm dealing with the following issue: often when making recursive calls, I'm unable to properly code in a base case. For example, in this problem we have to return -1 if the amount of money cannot be made up by any combination of the coins. However, I also need to count up the fewest number of coins.
Well you sort of have two base cases here
If the amount state variable is zero, we are done counting, so return the count
If we run out of coins (xs) to count with and still didn't reach a zero-amount, then return -1
Otherwise we have the two recursion cases
oops: amount is less than 0 meaning the last coin (x) subtracted was too big – rewind and recurse without using this coin
default case: add 1 to count, subtract the coin (x) from amount, and recurse using the same set of coins (xs)
The only requirement for this to work is that the coins are first sorted in descending order
OK, so all of this is easily encoded in Ruby using an auxiliary helper (aux) to hold our state variables. Remember to initialize with a count of 0 and ensure that xs is sorted in descending order. - Note the sorting only happens once – not once per recursion
def fewest_coins amount, xs
def aux count, amount, (x,*xs)
if amount.zero?
count
elsif x.nil?
-1
elsif amount < 0
aux (count - 1), (amount + x), xs
else
aux (count + 1), (amount - x), [x, *xs]
end
end
aux 0, amount, xs.sort { |a,b| b <=> a }
end
fewest_coins 11, [1, 5, 2] # => 3
fewest_coins 2, [3] # => -1
fewest_coins 100, [1, 25, 10, 5] # => 4
Check your understanding
As an exercise, modify fewest_coins to output an array of coins that makes up the answer
# for example
fewest_coins 199, [1, 5, 10, 25, 50]
# => [50, 50, 50, 25, 10, 10, 1, 1, 1, 1]
You could do that as follows.
def count_ways(cents, coins)
if coins.size == 1
return (cents % coins.first) == 0 ? [cents/coins.first] : nil
end
coin, *remaining_coins = coins
(0..cents/coin).each_with_object([]) { |n, arr|
count_ways(cents-n*coin, remaining_coins).each { |a| arr << [n, *a] } }
end
def fewest(cents, coins)
count_ways(cents, coins)&.map(&:sum)&.min
end
fewest(11, [5,2,1])
#=> 3
fewest(199, [25,10,5,1])
#=> 13 (Let me guess: 7 quarters, 2 dimes, 4 pennies)
fewest(2, [3])
#=> nil
require 'time'
t = Time.now
fewest(2835, [25,10,5,1])
#=> 114
Time.now - t
#=> 7.6961 (seconds)
I took count_ways from my answer here.
The two &'s followed by . are Ruby's safe navigation operator, which was introduced in Ruby v2.3.0. Array#sum (and Enumerable#sum) first appeared in Ruby v2.4.0.
This question already has a really good answer that shows you exactly how to solve your problem, but I wanted to point out what was actually happening with your algorithm, so you know why it wasn't working for you.
Your first problem is that
coin_count(coins, amount - coins[i], min)
should be
coin_count(coins, amount - coins[i], coins.min)
Instead of passing along the smallest coin, you were passing along your min value, which you had set to Infinity, which made this statement checking if the amount was smaller than the smallest coin:
return -1 if amount < min_coin
actually check if the amount was smaller than infinity, which meant your coin_count is always returning -1. Which leads to the second problem:
1 + coin_count(coins, amount - coins[i], min)
#1 + -1 = 0
The frustrating thing about using -1 as an error in recursive programming is that -1 is an otherwise valid number and frequently causes logic problems. I would avoid using it entirely, but if your prompt or spec forces you to return it, i'd use it only at the last second. try:
def coin_change(coins, amount)
result = coin_count(coins, amount, coins.min)
return -1 if result == 1/0.0
return result
end
def coin_count(coins, amount, min_coin)
with_coin = min = 1.0/0
return 0 if amount == 0
return 1/0.0 if amount < min_coin
i = 0
while i < coins.length
with_coin = 1 + coin_count(coins, amount - coins[i], coins.min) if amount - coins[i] >= 0
min = [min, with_coin].min
i += 1
end
min
end
I changed your error number from -1 to infinity, which essentially makes your algorithm ignore invalid permutations since they're always sorted out by your .min(). the only way your function would return infinity in this case is if it were the smallest number returned, which only happens when there are no valid permutations. Then in fewest_coins I set it to check for infinity and return -1 instead.
Oh and by the way, there's a much easier way to loop through things in ruby:
coins.each do |coin|
with_coin = 1 + coin_count(coins, amount - coin, coins.min) if amount - coin >= 0
min = [min, with_coin].min
end
This definitely won’t be a smartest approach, it’s not the best performant one, and it might be time consuming for huge amounts, but it’s how I would do it in ruby:
def get coins, amount
coins = coins.sort
max = amount / coins.first + 1
(1..max).detect do |i|
result = coins.repeated_permutation(i).detect do |e|
e.reduce(:+) == amount
end
break result if result
end || -1
end
get [1, 2, 5], 11
#⇒ [1, 5, 5]
get [2], 3
#⇒ -1
I'm trying to improve my Ruby skills using the Project Euler series of questions and I'm wondering why this code does not work for this question: "Even Fibonacci numbers, Problem 2"
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
My code:
def fibo(n)
first, second, sequence = 0,1,[]
for e in n
first, second = second, first + second
sequence << e if e%2 == 0
end
sequence.inject(:+)
end
puts fibo(4000000)
Any help would be appreciated!
In the line:
for e in n
4,000,000 is being substituted for n, so you are saying:
for e in 4000000
which is not a valid statement - you cannot iterate on an integer.
If you would like to iterate through all the values from 0 to n, try:
for e in (0..n)
This iterates through the values in the range 0 to n.
However, there is a deeper problem here. It looks as though you want to iterate up to the value 4000000, but instead your code would iterate through the first 4000000 Fibonacci numbers, which is much more than you want. You may want to consider saying:
while second <= 4000000
I suggest you check out Ruby Koans if you're starting out with Ruby. It's a fun way of getting used to the ways of the language.
That said your code is not calculating Fibonacci correctly, it's not summing the Fibonacci numbers and also has some other errors (for e in n is not valid because n is not an Enumerator type). Fix it like this:
def fibo(n)
first, second, sum = 0, 1, 0
loop do
first, second = second, first + second
sum += second if second%2 == 0
break if second >= n
end
sum
end
Working on Problem 12 of Project Euler:
The sequence of triangle numbers is generated by adding the natural numbers. So the 7th triangle number would be 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28. The first ten terms would be:
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...
Let us list the factors of the first seven triangle numbers:
1: 1
3: 1,3
6: 1,2,3,6
10: 1,2,5,10
15: 1,3,5,15
21: 1,3,7,21
28: 1,2,4,7,14,28
We can see that 28 is the first triangle number to have over five divisors.
What is the value of the first triangle number to have over five hundred divisors?
Here's what I've got:
require 'reusable'
# The idea here is that 2^n is the smallest number with n factors,
# according to their definition, so it's a good place to start.
# It also happens to be a HUGE number, so I'm worried I'm thinking
# about this wrong. Did 4999 instead of 5000, just to make sure
# I didn't overshoot.
start = 2 * 4999
# The faster way to calculate the nth Triangle number
def nthTriangle(n)
n * (n + 1) / 2
end
def answer(num)
i = startingTriangle(num)
while true
triangle = i*(i+1)/2
puts triangle
factors = numFactors(triangle)
return "#{triangle} is triangle number #{i}, with #{factors} factors." if factors > num
i += 1
end
end
# Basic reversal of the nthTriangle thing to figure
# out which n to start with in the answer function.
def startingTriangle(n)
power = n - 2
sqrt(power * 2).to_i - 1
end
puts answer(5000)
And that required file (where I'm trying to put methods I'll reuse in a bunch of Euler problems):
def primesUpTo(n)
nums = [0, 0] + (2..n).to_a
(2..sqrt(n).to_i+1).each do |i|
if nums[i].nonzero?
(i**2..n).step(i) {|m| nums[m] = 0}
end
end
nums.find_all {|m| m.nonzero?}
end
def prime?(n)
test = primesUpTo(sqrt(n).to_i)
test.each do |i|
if n % i == 0
return false
end
end
true
end
# Just for faster, more intuitive (to me) array summing
def sum(array)
array.inject(0) {|s, n| s + n }
end
# Ditto
def product(array)
array.inject(1) {|p, n| p * n}
end
# I don't like typing the 'Math.'
def sqrt(n)
Math.sqrt(n)
end
# Returns an array of arrays of the prime factors of num
# Form [[factor1, power1],[factor2, power2]]
# Ex: primeFactors(12) == [[2,2],[3,1]]
def primeFactors(n)
array = []
# 2 3
primesUpTo((n/2).to_i+1).select{ |i| n % i == 0 }.each do |p|
pcount = 1
n = n / p
while n % p == 0
pcount += 1
n = n / p
end
array << [p, pcount]
end
array
end
# Returns the number of factors a number has
# INCLUDING both the number itself and 1
# ex: numFactors(28) = 6
def numFactors(n)
return 2 if prime?(n)
product = 1
primeFactors(n).each do |i|
product *= i[1] + 1
end
product
end
My problem is that my code is really super slow. If I start at 1 instead of my start number, it takes a minute + before it gets to like 200000 (nowhere near 2^4999). But apart from scrapping the library prime-number solution and adding all primes to an array I keep referring to -- which I feel would only make it a small amount faster -- I can't think of how to make this much faster. And it needs to be WAY faster.
Am I thinking about this all wrong? Any suggestions?
Also useful would be any suggestions for how to improve the efficiency of any of my library methods, which I'll probably be using again and again. I wanted to make them from scratch so I understood them, but I'm afraid they're very inefficient.
From your code:
The idea here is that 2^n is the smallest number with n factors
From the stated Project Euler task:
We can see that 28 is the first triangle number to have over five divisors.
I'm not sure why you think 2^n is the smallest number with n factors, but the example given in the question clearly proves your assumption wrong, as 2^5 = 32, which is greater than 28.
My solution starts the search at 1 and is reasonably efficient. I don't use primes at all.
Addendum: For the sake of completeness, the other large issue besides starting at a number far too high is searching for greater than 5000 divisors rather than greater than 500, as you noticed and pointed out in the comments.