Related
Given a positive integer n I wish to find the largest integer m comprised of the digits contained in n that is less than n.
The code is to return m unless one of the following results obtain, in which case -1 it should be returned.
there is no possible variation;
if the number of digits isn't equal to the input;
if the first digit of the output == 0;
My code works, but it takes too long when "n" is a huge number! I believe it's because of the method #Permutation but I'm not sure. Can anyone shed a light on this?
Here's my code
def next_smaller (n)
new = n.to_s.split("").permutation.to_a.map { |n| n.join.to_i }
res = new.sort.reverse.select { |x| x < n }.first
res_arr = res.to_s.split("")
res.nil? || res_arr.count != n.to_s.split("").count || res_arr[0] == 0 ? -1 : res
end
Thank you
UPD: The code below works incorrectly with some input.
It is better to skip the generation of all permutations. Array#permutation can take a block of code:
def fast_next_smaller(number)
number.digits.reverse.permutation do |array|
next if array.first == 0
target_number = array.join.to_i
next if target_number == number
return target_number if target_number < number
end
-1
end
fast_next_smaller(907) #=> 790
fast_next_smaller(513) #=> 153
fast_next_smaller(153) #=> 135
fast_next_smaller(135) #=> -1
Here is the benchmark:
require 'benchmark'
n = 1000
Benchmark.bm do |x|
x.report('next_smaller') { n.times { next_smaller(rand(1_000_000..9_000_000)) } }
x.report('fast_next_smaller') { n.times { fast_next_smaller(rand(1_000_000..9_000_000)) } }
end
user system total real
next_smaller 4.433144 0.000000 4.433144 ( 4.433113)
fast_next_smaller 0.041333 0.000003 0.041336 ( 0.041313)
# With a very big number
puts Benchmark.measure { fast_next_smaller(5312495046546651005896) }
0.000000 0.000184 0.000184 ( 0.000176)
This should generally be pretty quick.
Code
def largest(n)
arr = n.to_s.chars.map(&:to_i)
nbr_chars = arr.size
case nbr_chars
when 1
-1
when 2
m = arr.reverse.join.to_i
m < 10 || m >= n ? -1 : m
else
(2..nbr_chars).each do |m|
fix_digits = arr[0,nbr_chars-m]
var_digits = arr[-m..-1]
if var_digits == var_digits.sort
return -1 if m == nbr_chars
else
a = solve_for_last_m_digits(var_digits)
if a.nil?
next if m < nbr_chars
return -1
else
x = (fix_digits + a).join.to_i
return x >= 10**(nbr_chars-1) ? x : -1
end
end
end
-1
end
end
def solve_for_last_m_digits(a)
nbr_chars = a.size
a_as_int = a.join.to_i
x = a.permutation(nbr_chars).max_by do |b|
m = b.join.to_i
m < a_as_int ? m : 0
end
x.join.to_i < a_as_int ? x : nil
end
Examples
largest 907 #=> 790
largest 531 #=> 513
largest 2638 #=> 2386
largest 78436 #=> 78364
largest 1783435893 #=> 1783435839
largest 385395038954829678 #=> 385395038954828976
largest 135 #=> -1
largest 106 #=> -1
All of the calculations were effectively instantaneous.
Explanation
See Array#permutation and Enumerable#max_by.
It's easiest to explain the algorithm with an example. Suppose the given integer were:
n = 385395038954829678
Had the last two digits been 87, rather than 78, we could simply reverse them and we'd be finished. As it is 78, however, we conclude that there is no integer less n that can be obtained by permuting the last two digits of n.
Next we consider the last three digits, 678. After examine the six permutations of these 3 digits we find that none are smaller than 678, so we conclude that there is no integer less n that can be obtained by permuting the last three digits.
Actually I don't examine the 6 permutations of the digits of 678. Rather I infer that the digits of that number cannot be permuted to produce a number smaller than 678 because they are non-decreasing (6 <= 7 <= 8). That is the purpose of the fragment
if var_digits == var_digits.sort
return -1 if m == nbr_chars
If the digits of the entire string are non-decreasing (m == nbr_chars is true), we return -1; else m is incremented by one.
We therefore move on to examining the last 4 digits of the number, 9678. As the digits comprising 9678 are not non-decreasing we know that they can be permuted to produce a number smaller than 9678 (simply swap two consecutive digits that are decreasing). After examining the 24 permutations of those four digits we find the largest number less than 9678 is 8976. Clearly, there is no permutation of digits that would produce a number less than n but larger than n with the last 4 digits replaced by 8976. The integer of interest is therefore obtained by replacing the last four digits of 385395038954829678 with 8976, which is 385395038954828976.
As soon as the last n-digits of m are not non-decreasing we know they can be rearranged to produce one more more numbers smaller than m, the largest of which will be the replacement for the last n digits of m.
The last step is to execute:
return x >= 10**(nbr_chars-1) ? x : -1
Suppose the number were 106. The largest number less than 106 that can be obtained by permuting its digits is x = 61 (061). As 61 has one or more (here one) leading zeroes, we return -1. We know there is at least one leading zéro because nbr_chars #=> 3, 10**(nbr_chars -1) #=> 100and61 < 100`.
I have solved a Codewars kata, but I can not submit it because my code takes too long. A lot of people had this problem, but we can not see the solution. The problem is, that generating the prime numbers takes too long (more than 12s) (I generate the primes with a method).
In my computer, I can require the class Prime, and this solves the problem. But in Codewar one can not require the class Prime, therefore, my method of generating prime numbers is too slow.
Any help?
require "pry"
def primeFactors(n)
start_time = Time.now
puts start_time
# find prime numbers smaller than n
nums = (2..(n-1)).to_a
odd_nums = nums.select { |num| num.odd? }
primes = odd_nums.select do |num|
is_prime(num)
end
end_time = Time.now
duration = end_time - start_time
puts end_time
# divide until mod is 1
dividend = n
res_primes = []
while dividend > 1
primes.each do |prime| # prime divisor
new_dividend = dividend.to_f / prime
remainder = dividend % prime
if remainder.zero?
dividend = new_dividend
res_primes << prime
break
end
end
end
freqs = {}
res_primes.each do |res_prime|
freqs[res_prime] = res_primes.count(res_prime)
end
res_string = []
freqs.keys.each do |key|
if freqs[key] == 1
res_string << "(#{key})"
else
res_string << "(#{key}**#{freqs[key]})"
end
end
res_string.join
end
def is_prime(n)
(2..n/2).none?{|i| n % i == 0}
end
Well for starters you really only need to test to Math.sqrt(n).to_i + 1 that should help for larger n values.
This is because if a factor exists where n = a * b then either
If a == b == sqrt(n) # Basically the defn of sqrt
or
If a != b; a < sqrt(n); b > sqrt(n)
If both a and b are less than sqrt(n) then a * b < n
and
If both a and b are greater than sqrt(n) the a * b > n
Secondly, and this is more complex, you only need to test prime numbers to that limit. I could envision a scheme where primes are cached.
Hope this helps.
The more advanced option might look like this:
# Is this number a prime?
module PrimeChecker
#prime_cache = [2,3]
def self.prime?(n)
search_limit = Math.sqrt(n).to_i + 1
last_cache = #prime_cache[-1]
while last_cache < search_limit do
last_cache += 2
#prime_cache << last_cache if PrimeChecker.prime?(last_cache)
end
#prime_cache.each do |pn|
return true if pn > search_limit
return false if (n % pn) == 0
end
true
end
end
# Sample run
#
# 31 mysh>%=PrimeChecker.prime?(1_000_000_000_000)
# false
# Elapsed execution time = 1.592 seconds.
#
This running on an elderly machine with a slow CORE 2 Duo processor.
Write a function that prints out all the factors for each of the numbers 1 through 100.
Really amateur coder but here's my attempt so far.
def factors_numbers(n1,n2)
(n1..n2).each do |n|
factors = []
factors << 1 ##every number has a factor of 1
factors << n ##every number is a factor of itself
i = 1
while i < n
new_number = n % (n-i)
if new_number == 0 #if 0, divisible and that means two numbers are factors
factors << new_number
factors << (n-i)
end
i += 1
end
return factors
end
end
Here is an improved version of your code:
def factors_numbers(n1,n2)
all_factors = {}
(n1..n2).each do |n|
factors = []
(1..Math.sqrt(n).floor).each do |i|
remainder = n % i
if remainder == 0 #if 0, divisible and that means two numbers are factors
factors << i
factors << n/i
end
end
factors = factors.sort.uniq
puts "Factors of #{n}: #{factors.join(',')}"
all_factors[n]=[factors]
end
return all_factors
end
Do you want unique factors? That is, in the range 1-100, should I get the number 1 a hundred times, or only once?
The easiest way to do this is by leveraging the "inject" Enumerable method.
def find_all_factors_between(n1,n2)
(n1..n2).inject([]) do |factors, num|
factors + (1..num).inject([]) { |arry, test| num % test == 0 ? arry + [test] : arry }
end
end
One final thing to note is that Ruby has implicit returns; that is, as long as the output of the last line of your method is your factors variable, you don't have to say return factors.
And my entry would be:
def find_all_factors_between(n1, n2)
factors = -> (n) { (1..n).select {|i| n % i == 0} }
(n1..n2).each { |n| puts "Factors of #{n}: #{factors.(n).join(', ')}" }
end
find_all_factors_between(1,100)
Well, if you wanted to do it with enumerables, there's always
def factor_numbers(rng)
factors = rng.map do |n|
(1..Math.sqrt(n).floor) # search numbers <= square root
.select { |d| n % d == 0 } # find factors <= square root
.flat_map { |x| [x, n / x] } # combine with factors >= square root
.sort # order from least to greatest
.uniq # remove dupes (basically the square root)
end
Hash[rng.zip(factors)] # rng = keys, factors = values
end
puts factor_numbers(1..100)
It's not the most efficient, but my point is just that many of the for/while constructs you'd see in languages like C or JavaScript can be expressed in other ways in Ruby.
(n1..n2).each{|x| print "#{x}: #{(1..x).select{|y| x % y == 0}}\n"}
That oughta do it :)
edit: Implemented Cary Swoveland's suggestion
def factor_nums(n1,n2)
all_factors = {}
(n1..n2).each do |n|
factors = []
(1..n).each do |i|
remainder = n % i
factors << i if remainder == 0
end
all_factors[n] = factors
end
return all_factors
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.
I am learning Ruby and doing some math stuff. One of the things I want to do is generate prime numbers.
I want to generate the first ten prime numbers and the first ten only. I have no problem testing a number to see if it is a prime number or not, but was wondering what the best way is to do generate these numbers?
I am using the following method to determine if the number is prime:
class Integer < Numeric
def is_prime?
return false if self <= 1
2.upto(Math.sqrt(self).to_i) do |x|
return false if self%x == 0
end
true
end
end
In Ruby 1.9 there is a Prime class you can use to generate prime numbers, or to test if a number is prime:
require 'prime'
Prime.take(10) #=> [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
Prime.take_while {|p| p < 10 } #=> [2, 3, 5, 7]
Prime.prime?(19) #=> true
Prime implements the each method and includes the Enumerable module, so you can do all sorts of fun stuff like filtering, mapping, and so on.
If you'd like to do it yourself, then something like this could work:
class Integer < Numeric
def is_prime?
return false if self <= 1
2.upto(Math.sqrt(self).to_i) do |x|
return false if self%x == 0
end
true
end
def next_prime
n = self+1
n = n + 1 until n.is_prime?
n
end
end
Now to get the first 10 primes:
e = Enumerator.new do |y|
n = 2
loop do
y << n
n = n.next_prime
end
end
primes = e.take 10
require 'prime'
Prime.first(10) # => [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
Check out Sieve of Eratosthenes. This is not Ruby specific but it is an algorithm to generate prime numbers. The idea behind this algorithm is that you have a list/array of numbers say
2..1000
You grab the first number, 2. Go through the list and eliminate everything that is divisible by 2. You will be left with everything that is not divisible by 2 other than 2 itself (e.g. [2,3,5,7,9,11...999]
Go to the next number, 3. And again, eliminate everything that you can divide by 3. Keep going until you reach the last number and you will get an array of prime numbers. Hope that helps.
http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
People already mentioned the Prime class, which definitely would be the way to go. Someone also showed you how to use an Enumerator and I wanted to contribute a version using a Fiber (it uses your Integer#is_prime? method):
primes = Fiber.new do
Fiber.yield 2
value = 3
loop do
Fiber.yield value if value.is_prime?
value += 2
end
end
10.times { p primes.resume }
# First 10 Prime Numbers
number = 2
count = 1
while count < 10
j = 2
while j <= number
break if number%j == 0
j += 1
end
if j == number
puts number
count += 1
end
number += 1
end
Implemented the Sieve of Eratosthene (more or less)
def primes(size)
arr=(0..size).to_a
arr[0]=nil
arr[1]=nil
max=size
(size/2+1).times do |n|
if(arr[n]!=nil) then
cnt=2*n
while cnt <= max do
arr[cnt]=nil
cnt+=n
end
end
end
arr.compact!
end
Moreover here is a one-liner I like a lot
def primes_c a
p=[];(2..a).each{|n| p.any?{|l|n%l==0}?nil:p.push(n)};p
end
Of course those will find the primes in the first n numbers, not the first n primes, but I think an adaptation won't require much effort.
Here is a way to generate the prime numbers up to a "max" argument from scratch, without using Prime or Math. Let me know what you think.
def prime_test max
primes = []
(1..max).each {|num|
if
(2..num-1).all? {|denom| num%denom >0}
then
primes.push(num)
end
}
puts primes
end
prime_test #enter max
I think this may be an expensive solution for very large max numbers but seems to work well otherwise:
def multiples array
target = array.shift
array.map{|item| item if target % item == 0}.compact
end
def prime? number
reversed_range_array = *(2..number).reverse_each
multiples_of_number = multiples(reversed_range_array)
multiples_of_number.size == 0 ? true : false
end
def primes_in_range max_number
range_array = *(2..max_number)
range_array.map{|number| number if prime?(number)}.compact
end
class Numeric
def prime?
return self == 2 if self % 2 == 0
(3..Math.sqrt(self)).step(2) do |x|
return false if self % x == 0
end
true
end
end
With this, now 3.prime? returns true, and 6.prime? returns false.
Without going to the efforts to implement the sieve algorithm, time can still be saved quickly by only verifying divisibility until the square root, and skipping the odd numbers. Then, iterate through the numbers, checking for primeness.
Remember: human time > machine time.
I did this for a coding kata and used the Sieve of Eratosthenes.
puts "Up to which number should I look for prime numbers?"
number = $stdin.gets.chomp
n = number.to_i
array = (1..n).to_a
i = 0
while array[i]**2 < n
i = i + 1
array = array.select do |element|
element % array[i] != 0 || element / array[i] == 1
end
end
puts array.drop(1)
Ruby: Print N prime Numbers
http://mishra-vishal.blogspot.in/2013/07/include-math-def-printnprimenumbernoofp.html
include Math
def print_n_prime_number(no_of_primes=nil)
no_of_primes = 100 if no_of_primes.nil?
puts "1 \n2"
count = 1
number = 3
while count < no_of_primes
sq_rt_of_num = Math.sqrt(number)
number_divisible_by = 2
while number_divisible_by <= sq_rt_of_num
break if(number % number_divisible_by == 0)
number_divisible_by = number_divisible_by + 1
end
if number_divisible_by > sq_rt_of_num
puts number
count = count+1
end
number = number + 2
end
end
print_n_prime_number
Not related at all with the question itself, but FYI:
if someone doesn't want to keep generating prime numbers again and again (a.k.a. greedy resource saver)
or maybe you already know that you must to work with subsequent prime numbers in some way
other unknown and wonderful cases
Try with this snippet:
require 'prime'
for p in Prime::Generator23.new
# `p` brings subsequent prime numbers until the end of the days (or until your computer explodes)
# so here put your fabulous code
break if #.. I don't know, I suppose in some moment it should stop the loop
end
fp
If you need it, you also could use another more complex generators as Prime::TrialDivisionGenerator or Prime::EratosthenesGenerator. More info
Here's a super compact method that generates an array of primes with a single line of code.
def get_prime(up_to)
(2..up_to).select { |num| (2...num).all? { |div| (num % div).positive? } }
end
def get_prime(number)
(2..number).each do |no|
if (2..no-1).all? {|num| no % num > 0}
puts no
end
end
end
get_prime(100)