Выбрать только дробную часть значения числа

Я считаю, что существует более простой подход: изучите палиндромы, опускающиеся от самого большого продукта двух трехзначных чисел, выбирая первый палиндром с двумя трехзначными факторами.

Вот код Ruby:

require './palindrome_range'
require './prime'

def get_3_digit_factors(n)
  prime_factors = Prime.factors(n)

  rf = [prime_factors.pop]
  rf << prime_factors.shift while rf.inject(:*) < 100 || prime_factors.inject(:*) > 999

  lf = prime_factors.inject(:*)
  rf = rf.inject(:*)

  lf < 100 || lf > 999 || rf < 100 || rf > 999 ? [] : [lf, rf]
end

def has_3_digit_factors(n)
  return !get_3_digit_factors(n).empty?
end

pr = PalindromeRange.new(0, 999 * 999)
n = pr.downto.find {|n| has_3_digit_factors(n)}
puts "Found #{n} - Factors #{get_3_digit_factors(n).inspect}, #{Prime.factors(n).inspect}"

prime.rb:

class Prime

  class<<self

    # Collect all prime factors
    # -- Primes greater than 3 follow the form of (6n +/- 1)
    #    Being of the form 6n +/- 1 does not mean it is prime, but all primes have that form
    #    See http://primes.utm.edu/notes/faq/six.html
    # -- The algorithm works because, while it will attempt non-prime values (e.g., (6 *4) + 1 == 25),
    #    they will fail since the earlier repeated division (e.g., by 5) means the non-prime will fail.
    #    Put another way, after repeatedly dividing by a known prime, the remainder is itself a prime
    #    factor or a multiple of a prime factor not yet tried (e.g., greater than 5).
    def factors(n)
      square_root = Math.sqrt(n).ceil
      factors = []

      while n % 2 == 0
        factors << 2
        n /= 2
      end

      while n % 3 == 0
        factors << 3
        n /= 3
      end

      i = 6
      while i < square_root
        [(i - 1), (i + 1)].each do |f|
          while n % f == 0
            factors << f
            n /= f
          end
        end

        i += 6
      end

      factors << n unless n == 1
      factors
    end

  end

end

palindrome_range.rb:

class PalindromeRange

  FIXNUM_MAX = (2**(0.size * 8 -2) -1)

  def initialize(min = 0, max = FIXNUM_MAX)
    @min = min
    @max = max
  end

  def downto
    return enum_for(:downto) unless block_given?

    n = @max
    while n >= @min
      yield n if is_palindrome(n)
      n -= 1
    end
    nil
  end

  def each
    return upto
  end

  def upto
    return enum_for(:downto) unless block_given?

    n = @min
    while n <= @max
      yield n if is_palindrome(n)
      n += 1
    end
    nil
  end

  private

  def is_palindrome(n)
    s = n.to_s
    i = 0
    j = s.length - 1
    while i <= j
      break if s[i] != s[j]
      i += 1
      j -= 1
    end
    i > j
  end

end
18
задан starkeen 15 June 2015 в 15:47
поделиться