LoginSignup
0
2

More than 3 years have passed since last update.

初学者によるプログラミングMemo #22 素因数分解

Last updated at Posted at 2020-02-06

はじめに

今回は素因数分解のお話です
最近問題を解くことが多くなって、アルゴリズム関係に面白みを見出しています
Rails関係なくても書いている下記はすでに決まり文句ともなりました
なお、本記述はMacにおいて、Railsでの開発を前提としています
また、まだまだひよっこですので、不備等ございましたらご指摘いただけると幸いです→よく間違えますが、生暖かく見守ってくださると幸いです
*例により、スマートなコードがコメント欄に乗っていますので、是非そちらもご参照ください
私の記事は、皆さんのご指摘・ご教示の上で成り立っています、ありがとうございます

目次

  • 素因数分解とは
  • 問題を解いてみる

素因数分解とは

素因数分解とは、ある正の整数を素数の積で表すことです
なんのこっちゃですかね?
具体的に見てみましょう
例えば「30」を素因数分解してみましょう

30 = 10 * 3
10 = 5 * 2
# ↑を合わせるとこう(↓)なる
30 = 2 * 3 * 5

2,3,5はいづれも素数ですね
このように、元の数を素数を使った掛け算で表すことを、素因数分解と言います

問題を解いてみる

さて、本題です
素因数分解を用いた問題を解いてみましょう

問題
"27156"の約数のうち、"100"以下の約数を全て答えよ
さあ、困った
なんせ約数の話は一切していないですからね
まあでも約数は小学生の範囲なんで割愛します、流石にわかるでしょうから

さて、お察しかと思いますが、素因数分解を利用することで、約数を求めることができます
順番にやっていきましょう
なお今回は、前々回の素数の話を使いますので、先にご覧になることを推奨します
メソッドはここに載ってます

#挙動確かめるために"20"で行います
require 'prime'

20.prime_division.each do |prime|
  p prime
end

# => [2, 2]
#    [5, 1]

prime_divisionメソッドを使うと、素因数分解を自動で行ってくれます便利ですねー、いや、本当にありがたい
で、返り値はご覧の通り、"[素数,その数]"となります
ではこの性質を利用してみましょう

require 'prime'

primes = []

20.prime_division.each do |prime|
  prime[1].times {primes << prime[0]}
end

p primes
# => [2, 2, 5]

素因数分解ができてますね
解説します
先ほどの返り値を元に、"primes"に"prime[0]"(素数自体)を代入しています
しかし、それだけでは1回しか代入されないので、その前に"times"メソッドを使って、"prime[1]"(素数の数)の回数分代入処理を行ってやります
これで、無事素因数分解ができました
あとは約数を作らないといけませんね

約数を作る

さて、問題ももう後半に差し掛かりました
あとはこれを組み合わせてあげれば約数が出ますね
そうです組み合わせです
書いていきましょう

require 'prime'
primes = []
divisors = []

20.prime_division.each do |prime|
  prime[1].times {primes << prime[0]}
end
1.upto(primes.size) do |i|
  primes.combination(i) do |prime|
    divisors << prime.inject{|a,b| a *= b}
  end
end

p divisors

# => [2, 2, 5, 4, 10, 10, 20]

先に挙動の解説をします
"combination"メソッドを使って、組み合わせを作ります
組み合わせる数は"primes"に入っている要素分行うので、その前に、"upto"メソッドを使って、数を回します
"prime.inject{|a,b| a *= b}"は、組み合わせで持ってきた各項を掛け算してもらうための処理です

うまいこといきまし…ん?
なんかおかしいですね、2点ありますが何かわかりますか?

まず、"2"と"10"が2回出てきてしまっています

そして…

"1"がないですね

致命的です、これではいけません

1がない

修正を加えます

require 'prime'
primes = []
divisors = [1] # <= ここ

20.prime_division.each do |prime|
  prime[1].times {primes << prime[0]}
end
1.upto(primes.size) do |i|
  primes.combination(i) do |prime|
    divisors << prime.inject{|a,b| a *= b}
  end
end

divisors.uniq! # <= ここ

p divisors

# => [1, 2, 5, 4, 10, 20]

これでいけましたね
"divisors = [1]"はなんか無理やり感があってあまり好きではないですが、仕方ありません(←成長を止める要因)
そして"divisors.uniq!"で、重複を削除しています

ここまでくればもう完成です

require 'prime'
primes = []
divisors = [1]
ans = []

27156.prime_division.each do |prime|
  prime[1].times {primes << prime[0]}
end
1.upto(primes.size) do |i|
  primes.combination(i) do |prime|
    divisors << prime.inject{|a,b| a *= b}
  end
end

divisors.uniq!
for i in divisors
  if i <= 100
    ans << i
  end
end

p ans

# => [1, 2, 3, 31, 73, 4, 6, 62, 93, 12]

できました
が、数字の並びが気持ち悪いので、"sort!"しましょう

今回の完成形

ついでにおなじみの対話形式に変えちゃいましょう

require 'prime'

def divisor(x,y)
  primes = []
  divisors = [1]
  ans = []
  x.prime_division.each do |prime|
    prime[1].times {primes << prime[0]}
  end
  1.upto(primes.size) do |i|
    primes.combination(i) do |prime|
      divisors << prime.inject{|a,b| a *= b}
    end
  end
  divisors = divisors.uniq.sort
  for i in divisors
    if i <= y
      ans << i
    end
  end
  return ans
end

p "ある数の約数のうち、決まった数値以下の約数を求めたいん?そんなんうちに任しとき"
p "ほんならまず約数を求めたい数を教えてやー"
x = gets.to_i
p "ありがとう、次はなんぼ以下の約数求めなあかんか教えてや"
y = gets.to_i
if x != 0 && y != 0
  if x <= y
    p "なんでやねん!そんなん約数全部に決まってるやん"
    p divisor(x,y)
  else
    p "うちの労働力は高うつくで(笑)"
    p divisor(x,y)
  end
else
  p "もぅ、いけずせんと、ちゃんと入力して!!"
end

以上、終わり!!

0
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2